Browse Source

refactor file io -> path nio

Jason Rivard 2 years ago
parent
commit
1559d191a7
85 changed files with 832 additions and 772 deletions
  1. 1 2
      data-service/src/main/java/password/pwm/receiver/Settings.java
  2. 10 27
      data-service/src/main/java/password/pwm/receiver/Storage.java
  3. 5 3
      lib-util/src/main/java/password/pwm/util/java/JavaHelper.java
  4. 28 43
      onejar/src/main/java/password/pwm/onejar/ArgumentParser.java
  5. 7 7
      onejar/src/main/java/password/pwm/onejar/OnejarConfig.java
  6. 26 15
      onejar/src/main/java/password/pwm/onejar/OnejarMain.java
  7. 36 36
      onejar/src/main/java/password/pwm/onejar/TomcatOnejarRunner.java
  8. 1 1
      server/src/main/java/password/pwm/EnvironmentProperty.java
  9. 10 10
      server/src/main/java/password/pwm/FileLocker.java
  10. 1 1
      server/src/main/java/password/pwm/PwmAboutProperty.java
  11. 19 16
      server/src/main/java/password/pwm/PwmApplication.java
  12. 16 18
      server/src/main/java/password/pwm/PwmApplicationUtil.java
  13. 18 20
      server/src/main/java/password/pwm/PwmEnvironment.java
  14. 46 38
      server/src/main/java/password/pwm/config/stored/ConfigurationFileManager.java
  15. 17 15
      server/src/main/java/password/pwm/health/DebugOutputService.java
  16. 1 1
      server/src/main/java/password/pwm/health/LocalDBHealthChecker.java
  17. 32 29
      server/src/main/java/password/pwm/http/ContextManager.java
  18. 3 1
      server/src/main/java/password/pwm/http/servlet/admin/AppDashboardData.java
  19. 2 2
      server/src/main/java/password/pwm/http/servlet/admin/system/ConfigManagerLocalDBServlet.java
  20. 2 2
      server/src/main/java/password/pwm/http/servlet/admin/system/ConfigManagerServlet.java
  21. 2 0
      server/src/main/java/password/pwm/http/servlet/resource/CacheKey.java
  22. 4 2
      server/src/main/java/password/pwm/http/servlet/resource/FileResource.java
  23. 10 7
      server/src/main/java/password/pwm/http/servlet/resource/RealFileResource.java
  24. 11 20
      server/src/main/java/password/pwm/http/servlet/resource/ResourceFileRequest.java
  25. 39 33
      server/src/main/java/password/pwm/http/servlet/resource/ResourceServletConfiguration.java
  26. 23 24
      server/src/main/java/password/pwm/http/servlet/resource/ResourceServletService.java
  27. 33 29
      server/src/main/java/password/pwm/svc/db/JDBCDriverLoader.java
  28. 4 3
      server/src/main/java/password/pwm/svc/secure/AbstractSecureService.java
  29. 2 2
      server/src/main/java/password/pwm/svc/secure/SecureService.java
  30. 8 8
      server/src/main/java/password/pwm/util/OnejarHelper.java
  31. 3 3
      server/src/main/java/password/pwm/util/cli/CliEnvironment.java
  32. 21 21
      server/src/main/java/password/pwm/util/cli/MainClass.java
  33. 7 9
      server/src/main/java/password/pwm/util/cli/MainOptions.java
  34. 8 6
      server/src/main/java/password/pwm/util/cli/commands/ConfigDeleteCommand.java
  35. 5 4
      server/src/main/java/password/pwm/util/cli/commands/ConfigNewCommand.java
  36. 7 4
      server/src/main/java/password/pwm/util/cli/commands/ConfigResetHttpsCommand.java
  37. 9 6
      server/src/main/java/password/pwm/util/cli/commands/ExportAuditCommand.java
  38. 12 8
      server/src/main/java/password/pwm/util/cli/commands/ExportHttpsKeyStoreCommand.java
  39. 10 7
      server/src/main/java/password/pwm/util/cli/commands/ExportHttpsTomcatConfigCommand.java
  40. 6 5
      server/src/main/java/password/pwm/util/cli/commands/ExportLocalDBCommand.java
  41. 5 5
      server/src/main/java/password/pwm/util/cli/commands/ExportLogsCommand.java
  42. 3 3
      server/src/main/java/password/pwm/util/cli/commands/ExportResponsesCommand.java
  43. 7 5
      server/src/main/java/password/pwm/util/cli/commands/ExportStatsCommand.java
  44. 6 5
      server/src/main/java/password/pwm/util/cli/commands/ExportWordlistCommand.java
  45. 9 6
      server/src/main/java/password/pwm/util/cli/commands/ImportHttpsKeyStoreCommand.java
  46. 2 2
      server/src/main/java/password/pwm/util/cli/commands/ImportLocalDBCommand.java
  47. 9 9
      server/src/main/java/password/pwm/util/cli/commands/ImportPropertyConfigCommand.java
  48. 5 5
      server/src/main/java/password/pwm/util/cli/commands/ImportResponsesCommand.java
  49. 9 6
      server/src/main/java/password/pwm/util/cli/commands/ResponseStatsCommand.java
  50. 5 6
      server/src/main/java/password/pwm/util/cli/commands/UserReportCommand.java
  51. 16 16
      server/src/main/java/password/pwm/util/debug/FileInfoDebugItemGenerator.java
  52. 24 10
      server/src/main/java/password/pwm/util/debug/RootFileSystemDebugItemGenerator.java
  53. 14 0
      server/src/main/java/password/pwm/util/i18n/LocaleHelper.java
  54. 96 55
      server/src/main/java/password/pwm/util/java/FileSystemUtility.java
  55. 5 5
      server/src/main/java/password/pwm/util/localdb/AbstractJDBCLocalDB.java
  56. 5 4
      server/src/main/java/password/pwm/util/localdb/DerbyLocalDB.java
  57. 2 2
      server/src/main/java/password/pwm/util/localdb/LocalDB.java
  58. 4 3
      server/src/main/java/password/pwm/util/localdb/LocalDBAdaptor.java
  59. 7 9
      server/src/main/java/password/pwm/util/localdb/LocalDBFactory.java
  60. 3 3
      server/src/main/java/password/pwm/util/localdb/LocalDBProvider.java
  61. 6 6
      server/src/main/java/password/pwm/util/localdb/LocalDBUtility.java
  62. 3 3
      server/src/main/java/password/pwm/util/localdb/MemoryLocalDB.java
  63. 14 14
      server/src/main/java/password/pwm/util/localdb/XodusLocalDB.java
  64. 15 26
      server/src/main/java/password/pwm/util/logging/PwmLogManager.java
  65. 14 4
      server/src/main/java/password/pwm/util/logging/PwmLogUtil.java
  66. 6 26
      server/src/main/java/password/pwm/util/secure/SecureEngine.java
  67. 4 7
      server/src/main/java/password/pwm/util/secure/X509Utils.java
  68. 1 1
      server/src/test/java/password/pwm/EnvironmentPropertyTest.java
  69. 1 2
      server/src/test/java/password/pwm/config/DomainConfigTest.java
  70. 1 2
      server/src/test/java/password/pwm/config/profile/PasswordRuleReaderHelperTest.java
  71. 1 2
      server/src/test/java/password/pwm/config/stored/StoredConfigurationTest.java
  72. 9 10
      server/src/test/java/password/pwm/http/client/PwmHttpClientTest.java
  73. 1 1
      server/src/test/java/password/pwm/svc/event/CEFAuditFormatterTest.java
  74. 1 1
      server/src/test/java/password/pwm/svc/event/JsonAuditFormatterTest.java
  75. 1 1
      server/src/test/java/password/pwm/svc/event/LdapXmlUserHistoryTest.java
  76. 1 2
      server/src/test/java/password/pwm/svc/wordlist/WordlistServiceTest.java
  77. 1 2
      server/src/test/java/password/pwm/util/localdb/LocalDBBasicTest.java
  78. 2 3
      server/src/test/java/password/pwm/util/localdb/LocalDBLoggerExtendedTest.java
  79. 1 2
      server/src/test/java/password/pwm/util/localdb/LocalDBStoredQueueExtendedTest.java
  80. 1 2
      server/src/test/java/password/pwm/util/localdb/LocalDBStoredQueueTest.java
  81. 3 3
      server/src/test/java/password/pwm/util/localdb/TestHelper.java
  82. 1 2
      server/src/test/java/password/pwm/util/password/PasswordRuleChecksTest.java
  83. 1 1
      server/src/test/java/password/pwm/util/password/RandomPasswordGeneratorTest.java
  84. 1 1
      webapp/src/main/webapp/WEB-INF/jsp/configguide-start.jsp
  85. 1 1
      webapp/src/main/webapp/WEB-INF/jsp/configmanager-localdb.jsp

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

@@ -25,7 +25,6 @@ import password.pwm.util.java.EnumUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
@@ -83,7 +82,7 @@ public class Settings
     static Settings readFromFile( final String filename ) throws IOException
     {
         final Properties properties = new Properties();
-        final Path path = new File( filename ).toPath();
+        final Path path = Path.of( filename );
         try ( Reader reader = new InputStreamReader( Files.newInputStream( path ), StandardCharsets.UTF_8 ) )
         {
             properties.load( reader );

+ 10 - 27
data-service/src/main/java/password/pwm/receiver/Storage.java

@@ -31,11 +31,12 @@ import jetbrains.exodus.env.Store;
 import jetbrains.exodus.env.StoreConfig;
 import jetbrains.exodus.env.Transaction;
 import password.pwm.bean.TelemetryPublishBean;
-import password.pwm.util.json.JsonFactory;
 import password.pwm.util.java.StringUtil;
+import password.pwm.util.json.JsonFactory;
 
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Iterator;
 
@@ -49,23 +50,23 @@ public class Storage
 
     public Storage( final Settings settings ) throws IOException
     {
-        final String path = settings.getSetting( Settings.Setting.storagePath );
-        if ( path == null )
+        final String pathStr = settings.getSetting( Settings.Setting.storagePath );
+        if ( pathStr == null )
         {
             throw new IOException( "data path is not specified!" );
         }
 
-        final File dataPath = new File( path );
-        if ( !dataPath.exists() )
+        final Path dataPath = Path.of( pathStr );
+        if ( !Files.exists( dataPath ) )
         {
             throw new IOException( "data path '" + dataPath + "' does not exist" );
         }
 
-        final File storagePath = new File( dataPath.getAbsolutePath() + File.separator + "storage" );
-        mkdirs( storagePath );
+        final Path storagePath = dataPath.resolve( "storage" );
+        Files.createDirectories( storagePath );
 
         final EnvironmentConfig environmentConfig = new EnvironmentConfig();
-        environment = Environments.newInstance( storagePath.getAbsolutePath(), environmentConfig );
+        environment = Environments.newInstance( storagePath.toFile(), environmentConfig );
 
         LOGGER.info( () -> "environment open" );
 
@@ -219,22 +220,4 @@ public class Storage
             throw new UnsupportedOperationException( "remove not supported" );
         }
     }
-
-    static void mkdirs( final File file ) throws IOException
-    {
-        if ( file.exists() )
-        {
-            if ( file.isDirectory() )
-            {
-                return;
-            }
-            throw new IOException( "path already exists as file: " + file.getAbsolutePath() );
-        }
-
-        if ( !file.mkdirs() )
-        {
-            throw new IOException( "unable to create path " + file.getAbsolutePath() );
-        }
-    }
-
 }

+ 5 - 3
lib-util/src/main/java/password/pwm/util/java/JavaHelper.java

@@ -117,7 +117,7 @@ public final class JavaHelper
     public static long copy( final InputStream input, final OutputStream output )
             throws IOException
     {
-        return IOUtils.copyLarge( input, output, 0, -1 );
+        return input.transferTo( output );
     }
 
 
@@ -157,8 +157,10 @@ public final class JavaHelper
     public static void copy( final String input, final OutputStream output, final Charset charset )
             throws IOException
     {
-        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( input.getBytes( charset ) );
-        JavaHelper.copy( byteArrayInputStream, output );
+        try ( ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream( input.getBytes( charset ) ) )
+        {
+            byteArrayInputStream.transferTo( output );
+        }
     }
 
     public static long copyWhilePredicate(

+ 28 - 43
onejar/src/main/java/password/pwm/onejar/ArgumentParser.java

@@ -26,13 +26,13 @@ import org.apache.commons.cli.HelpFormatter;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.ParseException;
 
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.InetAddress;
 import java.net.ServerSocket;
 import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.SecureRandom;
 import java.util.Collections;
 import java.util.EnumMap;
@@ -111,10 +111,11 @@ public class ArgumentParser
         return null;
     }
 
-    private Map<Argument, String> mapFromProperties( final String filename ) throws ArgumentParserException
+    private Map<Argument, String> mapFromProperties( final String filename )
+            throws ArgumentParserException
     {
         final Properties props = new Properties();
-        try ( InputStream is = new FileInputStream( filename ) )
+        try ( InputStream is = Files.newInputStream( Path.of( filename ) ) )
         {
             props.load( is );
         }
@@ -180,15 +181,15 @@ public class ArgumentParser
 
         if ( argumentMap.containsKey( Argument.war ) )
         {
-            final File inputWarFile = new File( argumentMap.get( Argument.war ) );
-            if ( !inputWarFile.exists() )
+            final Path inputWarFile = Path.of( argumentMap.get( Argument.war ) );
+            if ( !Files.exists( inputWarFile ) )
             {
-                final String msg = "output war file " + inputWarFile.getAbsolutePath() + "does not exist";
+                final String msg = "output war file " + inputWarFile + "does not exist";
                 System.out.println( msg );
                 throw new IllegalStateException( msg );
             }
 
-            try ( InputStream inputStream = new FileInputStream( inputWarFile ) )
+            try ( InputStream inputStream = Files.newInputStream( inputWarFile ) )
             {
                 onejarConfig.war( inputStream );
             }
@@ -272,26 +273,26 @@ public class ArgumentParser
     }
 
 
-    private static File parseFileOption( final Map<Argument, String> argumentMap, final Argument argName )
+    private static Path parseFileOption( final Map<Argument, String> argumentMap, final Argument argName )
             throws ArgumentParserException
     {
         if ( !argumentMap.containsKey( argName ) )
         {
             throw new ArgumentParserException( "option " + argName + " required" );
         }
-        final File file = new File( argumentMap.get( argName ) );
+        final Path file = Path.of( argumentMap.get( argName ) );
         if ( !file.isAbsolute() )
         {
             throw new ArgumentParserException( "a fully qualified file path name is required for " + argName );
         }
-        if ( !file.exists() )
+        if ( !Files.exists( file ) )
         {
             throw new ArgumentParserException( "path specified by " + argName + " must exist" );
         }
         return file;
     }
 
-    private static File figureDefaultWorkPath(
+    private static Path figureDefaultWorkPath(
             final String localAddress,
             final String context,
             final int port,
@@ -302,29 +303,21 @@ public class ArgumentParser
         final String userHomePath = System.getProperty( "user.home" );
         if ( userHomePath != null && !userHomePath.isEmpty() )
         {
-            final File basePath = new File( userHomePath + File.separator
-                    + Resource.defaultWorkPathName.getValue() );
-
-            mkdirs( basePath );
-
-            final String workPath;
-            {
-                String workPathStr = basePath.getPath() + File.separator + "work"
-                        + "-"
-                        + escapeFilename( context )
-                        + "-"
-                        + escapeFilename( Integer.toString( port ) )
-                        + ( isCommandExec ? "-" + "cmd" : "" );
-
-                if ( localAddress != null && !localAddress.isEmpty() )
-                {
-                    workPathStr += "-" + escapeFilename( localAddress );
-
-                }
-                workPath = workPathStr;
-            }
-            final File workFile = new File( workPath );
-            mkdirs( workFile );
+            final Path basePath = Path.of( userHomePath ).resolve( Resource.defaultWorkPathName.getValue() );
+
+            final String escapedLocalAddr = ( localAddress != null && !localAddress.isEmpty() )
+                    ? "-" + escapeFilename( localAddress )
+                    : "";
+            final String workPath = "work"
+                    + "-"
+                    + escapeFilename( context )
+                    + "-"
+                    + escapeFilename( Integer.toString( port ) )
+                    + ( isCommandExec ? "-cmd" : "" )
+                    + escapedLocalAddr;
+
+            final Path workFile = basePath.resolve( workPath );
+            Files.createDirectories( workFile );
             OnejarMain.output( "using work directory: " + workPath );
             return workFile;
         }
@@ -361,12 +354,4 @@ public class ArgumentParser
         }
         return stringBuilder.toString();
     }
-
-    static void mkdirs( final File file ) throws IOException
-    {
-        if ( !file.mkdirs() && !file.exists() )
-        {
-            throw new IOException( "unable to create path " + file.getAbsolutePath() );
-        }
-    }
 }

+ 7 - 7
onejar/src/main/java/password/pwm/onejar/OnejarConfig.java

@@ -23,30 +23,30 @@ package password.pwm.onejar;
 import lombok.Builder;
 import lombok.Value;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Path;
 
 @Value
 @Builder
 class OnejarConfig
 {
     private int port;
-    private File applicationPath;
-    private File workingPath;
+    private Path applicationPath;
+    private Path workingPath;
     private InputStream war;
     private String context;
     private String localAddress;
     private String keystorePass;
     private String execCommand;
 
-    File getWarFolder( ) throws IOException
+    Path getWarFolder( ) throws IOException
     {
-        return new File( this.getWorkingPath().getAbsoluteFile() + File.separator + "war" );
+        return getWorkingPath().resolve( "war" );
     }
 
-    File getKeystoreFile( )
+    Path getKeystoreFile( )
     {
-        return new File( this.getWorkingPath().getAbsoluteFile() + File.separator + "keystore" );
+        return getWorkingPath().resolve( "keystore" );
     }
 }

+ 26 - 15
onejar/src/main/java/password/pwm/onejar/OnejarMain.java

@@ -23,7 +23,6 @@ package password.pwm.onejar;
 import org.apache.catalina.LifecycleException;
 
 import javax.servlet.ServletException;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Method;
@@ -38,6 +37,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
+import java.util.stream.Collectors;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 
@@ -78,16 +78,16 @@ public class OnejarMain
     {
         try
         {
-            purgeDirectory( onejarConfig.getWorkingPath().toPath() );
+            purgeDirectory( onejarConfig.getWorkingPath() );
             this.explodeWar( onejarConfig );
             final String cmdLine = onejarConfig.getExecCommand();
             final TomcatOnejarRunner runner = new TomcatOnejarRunner( this );
             final URLClassLoader classLoader = runner.warClassLoaderFromConfig( onejarConfig );
 
-            final Class pwmMainClass = classLoader.loadClass( "password.pwm.util.cli.MainClass" );
+            final Class<?> pwmMainClass = classLoader.loadClass( "password.pwm.util.cli.MainClass" );
             final Method mainMethod = pwmMainClass.getMethod( "main", String[].class );
             final List<String> cmdLineItems = new ArrayList<>( );
-            cmdLineItems.add( "-applicationPath=" + onejarConfig.getApplicationPath().getAbsolutePath() );
+            cmdLineItems.add( "-applicationPath=" + onejarConfig.getApplicationPath() );
             cmdLineItems.addAll( Arrays.asList( cmdLine.split( " " ) ) );
             final String[] arguments = cmdLineItems.toArray( new String[0] );
 
@@ -107,7 +107,7 @@ public class OnejarMain
         {
             try
             {
-                purgeDirectory( onejarConfig.getWorkingPath().toPath() );
+                purgeDirectory( onejarConfig.getWorkingPath() );
                 this.explodeWar( onejarConfig );
                 final TomcatOnejarRunner runner = new TomcatOnejarRunner( this );
                 Runtime.getRuntime().addShutdownHook( new ShutdownThread( runner ) );
@@ -178,38 +178,49 @@ public class OnejarMain
     {
         final InputStream warSource = onejarConfig.getWar();
         final ZipInputStream zipInputStream = new ZipInputStream( warSource );
-        final File outputFolder = onejarConfig.getWarFolder( );
+        final Path outputFolder = onejarConfig.getWarFolder( );
 
-        ArgumentParser.mkdirs( outputFolder );
+        Files.createDirectories( outputFolder );
 
         ZipEntry zipEntry = zipInputStream.getNextEntry();
 
         while ( zipEntry != null )
         {
             final String fileName = zipEntry.getName();
-            final File newFile = new File( outputFolder + File.separator + fileName );
+            final Path newFile = outputFolder.resolve( fileName );
 
             if ( !zipEntry.isDirectory() )
             {
-                ArgumentParser.mkdirs( newFile.getParentFile() );
-                Files.copy( zipInputStream, newFile.toPath() );
+                final Path parentDir = newFile.getParent();
+                if ( parentDir != null
+                        && newFile.startsWith( outputFolder )
+                        && parentDir.startsWith( outputFolder ) )
+                {
+                    Files.createDirectories( parentDir );
+                    Files.copy( zipInputStream, newFile );
+                }
             }
             zipEntry = zipInputStream.getNextEntry();
         }
+
         out( "deployed war" );
     }
 
     private void purgeDirectory( final Path rootPath )
             throws IOException
     {
-        if ( rootPath.toFile().exists() )
+        if ( Files.exists( rootPath ) )
         {
             out( "purging work directory: " + rootPath );
-            Files.walk( rootPath, FileVisitOption.FOLLOW_LINKS )
+            final List<Path> filePaths = Files.walk( rootPath, FileVisitOption.FOLLOW_LINKS )
                     .sorted( Comparator.reverseOrder() )
-                    .map( Path::toFile )
-                    .filter( file -> !rootPath.toString().equals( file.getPath() ) )
-                    .forEach( File::delete );
+                    .filter( path -> !rootPath.equals( path ) )
+                    .collect( Collectors.toList() );
+
+            for ( final Path path : filePaths )
+            {
+                Files.delete( path );
+            }
         }
     }
 }

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

@@ -28,7 +28,6 @@ import org.apache.coyote.http2.Http2Protocol;
 
 import javax.servlet.ServletException;
 import java.io.BufferedReader;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -38,7 +37,7 @@ import java.net.URL;
 import java.net.URLClassLoader;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
-import java.nio.file.Paths;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
@@ -84,20 +83,20 @@ public class TomcatOnejarRunner
         tomcat.setSilent( true );
 
         {
-            final File basePath = new File( onejarConfig.getWorkingPath().getPath() + File.separator + "b" );
-            ArgumentParser.mkdirs( basePath );
-            tomcat.setBaseDir( basePath.getAbsolutePath() );
+            final Path basePath = onejarConfig.getWorkingPath().resolve( "b" );
+            Files.createDirectories( basePath );
+            tomcat.setBaseDir( basePath.toString() );
         }
         {
-            final File basePath = new File( onejarConfig.getWorkingPath().getPath() + File.separator + "a" );
-            ArgumentParser.mkdirs( basePath );
-            tomcat.getServer().setCatalinaBase( basePath );
-            tomcat.getServer().setCatalinaHome( basePath );
+            final Path basePath = onejarConfig.getWorkingPath().resolve( "a" );
+            Files.createDirectories( basePath );
+            tomcat.getServer().setCatalinaBase( basePath.toFile() );
+            tomcat.getServer().setCatalinaHome( basePath.toFile() );
         }
         {
-            final File workPath = new File( onejarConfig.getWorkingPath().getPath() + File.separator + "w" );
-            ArgumentParser.mkdirs( workPath );
-            tomcat.getHost().setAppBase( workPath.getAbsolutePath() );
+            final Path workPath = onejarConfig.getWorkingPath().resolve( "w" );
+            Files.createDirectories( workPath );
+            tomcat.getHost().setAppBase( workPath.toString() );
         }
 
         tomcat.getHost().setAutoDeploy( false );
@@ -105,7 +104,7 @@ public class TomcatOnejarRunner
 
         deployRedirectConnector( tomcat, onejarConfig );
 
-        final String warPath = onejarConfig.getWarFolder().getAbsolutePath();
+        final String warPath = onejarConfig.getWarFolder().toString();
         tomcat.addWebapp( "/" + onejarConfig.getContext(), warPath );
 
         try
@@ -122,26 +121,27 @@ public class TomcatOnejarRunner
     }
 
     private void deployRedirectConnector( final Tomcat tomcat, final OnejarConfig onejarConfig )
-            throws IOException, ServletException
+            throws IOException
     {
         final String srcRootWebXml = "ROOT-redirect-webapp/WEB-INF/web.xml";
         final String srcRootIndex = "ROOT-redirect-webapp/WEB-INF/index.jsp";
 
-        final File redirBase = new File( onejarConfig.getWorkingPath().getAbsoluteFile() + File.separator + "redirectBase" );
-        ArgumentParser.mkdirs( redirBase );
+        final Path redirBase = onejarConfig.getWorkingPath().resolve( "redirectBase" );
+        Files.createDirectories( redirBase );
         {
-            ArgumentParser.mkdirs( new File ( redirBase.getAbsolutePath() + File.separator + "WEB-INF" ) );
+            final Path webInfPath = redirBase.resolve( "WEB-INF" );
+            Files.createDirectories( webInfPath );
             copyFileAndReplace(
                     srcRootWebXml,
-                    redirBase.getPath() + File.separator + "WEB-INF" + File.separator + "web.xml",
+                    webInfPath.resolve( "web.xml" ).toString(),
                     onejarConfig.getContext() );
             copyFileAndReplace(
                     srcRootIndex,
-                    redirBase.getPath() + File.separator +  "WEB-INF" + File.separator + "index.jsp",
+                    webInfPath.resolve( "index.jsp" ).toString(),
                     onejarConfig.getContext() );
         }
 
-        tomcat.addWebapp( "", redirBase.getAbsolutePath() );
+        tomcat.addWebapp( "", redirBase.toString() );
     }
 
 
@@ -159,7 +159,7 @@ public class TomcatOnejarRunner
         connector.setScheme( "https" );
         connector.addUpgradeProtocol( new Http2Protocol() );
         connector.setProperty( "SSLEnabled", "true" );
-        connector.setProperty( "keystoreFile", onejarConfig.getKeystoreFile().getAbsolutePath() );
+        connector.setProperty( "keystoreFile", onejarConfig.getKeystoreFile().toString() );
         connector.setProperty( "keystorePass", onejarConfig.getKeystorePass() );
         connector.setProperty( "keyAlias", OnejarMain.KEYSTORE_ALIAS );
         connector.setProperty( "clientAuth", "false" );
@@ -222,7 +222,7 @@ public class TomcatOnejarRunner
         try ( URLClassLoader classLoader = warClassLoaderFromConfig( onejarConfig ) )
         {
             final Class<?> pwmMainClass = classLoader.loadClass( "password.pwm.util.OnejarHelper" );
-            final String keystoreFile = onejarConfig.getKeystoreFile().getAbsolutePath();
+            final String keystoreFile = onejarConfig.getKeystoreFile().toString();
             final Method mainMethod = pwmMainClass.getMethod(
                     "onejarHelper",
                     String.class,
@@ -232,7 +232,7 @@ public class TomcatOnejarRunner
             );
 
             final String[] arguments = new String[] {
-                    onejarConfig.getApplicationPath().getAbsolutePath(),
+                    onejarConfig.getApplicationPath().toString(),
                     keystoreFile,
                     OnejarMain.KEYSTORE_ALIAS,
                     onejarConfig.getKeystorePass(),
@@ -248,13 +248,12 @@ public class TomcatOnejarRunner
     private void setupEnv( final OnejarConfig onejarConfig )
     {
         final String envVarPrefix = Resource.envVarPrefix.getValue() + ".";
-        System.setProperty( envVarPrefix + "applicationPath", onejarConfig.getApplicationPath().getAbsolutePath() );
+        System.setProperty( envVarPrefix + "applicationPath", onejarConfig.getApplicationPath().toString() );
         System.setProperty( envVarPrefix + "ManageHttps", Boolean.TRUE.toString() );
         System.setProperty( envVarPrefix + "OnejarInstance", Boolean.TRUE.toString() );
-        System.setProperty( envVarPrefix + "AutoExportHttpsKeyStoreFile", onejarConfig.getKeystoreFile().getAbsolutePath() );
+        System.setProperty( envVarPrefix + "AutoExportHttpsKeyStoreFile", onejarConfig.getKeystoreFile().toString() );
         System.setProperty( envVarPrefix + "AutoExportHttpsKeyStorePassword", onejarConfig.getKeystorePass() );
         System.setProperty( envVarPrefix + "AutoExportHttpsKeyStoreAlias", OnejarMain.KEYSTORE_ALIAS );
-
     }
 
 
@@ -271,7 +270,7 @@ public class TomcatOnejarRunner
             {
                 String contents = reader.lines().collect( Collectors.joining( "\n" ) );
                 contents = contents.replace( "[[[ROOT_CONTEXT]]]", rootcontext );
-                Files.write( Paths.get( destPath ), contents.getBytes( StandardCharsets.UTF_8 ) );
+                Files.write( Path.of( destPath ), contents.getBytes( StandardCharsets.UTF_8 ) );
             }
         }
     }
@@ -279,20 +278,21 @@ public class TomcatOnejarRunner
     URLClassLoader warClassLoaderFromConfig( final OnejarConfig onejarConfig )
             throws IOException
     {
-        final File warPath = onejarConfig.getWarFolder();
-        final File webInfPath = new File( warPath.getAbsolutePath() + File.separator + "WEB-INF" + File.separator + "lib" );
-        final File[] jarFiles = webInfPath.listFiles();
-        final List<URL> jarURLList = new ArrayList<>();
-        if ( jarFiles != null )
+        final Path warPath = onejarConfig.getWarFolder();
+        final Path webInfLibPath = warPath.resolve( "WEB-INF" ).resolve( "lib" );
+        final List<Path> jarFiles = Files.list( webInfLibPath )
+                .filter( path -> path.getFileName().toString().endsWith( ".jar" ) )
+                .collect( Collectors.toList() );
+
+        final List<URL> jarURLList = new ArrayList<>( jarFiles.size() );
+        for ( final Path jarFile : jarFiles )
         {
-            for ( final File jarFile : jarFiles )
-            {
-                jarURLList.add( jarFile.toURI().toURL() );
-            }
+            jarURLList.add( jarFile.toUri().toURL() );
         }
         return URLClassLoader.newInstance( jarURLList.toArray( new URL[0] ) );
     }
 
+
     public void shutdown() throws LifecycleException
     {
         if ( tomcat != null )

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

@@ -157,7 +157,7 @@ public enum EnvironmentProperty
                 return Collections.emptyMap();
             }
 
-            final Path propFilePath = Path.of( appPath.toString(), PwmConstants.DEFAULT_ENVIRONMENT_PROPERTIES_FILENAME );
+            final Path propFilePath = appPath.resolve( PwmConstants.DEFAULT_ENVIRONMENT_PROPERTIES_FILENAME );
 
             if ( !Files.exists( propFilePath ) )
             {

+ 10 - 10
server/src/main/java/password/pwm/FileLocker.java

@@ -28,12 +28,12 @@ import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.io.StringWriter;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileLock;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Properties;
 
@@ -43,13 +43,13 @@ class FileLocker
 
     private final PwmEnvironment pwmEnvironment;
     private FileLock lock;
-    private final File lockfile;
+    private final Path lockfile;
 
     FileLocker( final PwmEnvironment pwmEnvironment )
     {
         this.pwmEnvironment = pwmEnvironment;
         final String lockfileName = pwmEnvironment.getConfig().readAppProperty( AppProperty.APPLICATION_FILELOCK_FILENAME );
-        lockfile = new File( pwmEnvironment.getApplicationPath(), lockfileName );
+        lockfile = pwmEnvironment.getApplicationPath().resolve( lockfileName );
     }
 
     private boolean lockingAllowed( )
@@ -68,22 +68,22 @@ class FileLocker
         {
             try
             {
-                final RandomAccessFile file = new RandomAccessFile( lockfile, "rw" );
+                final RandomAccessFile file = new RandomAccessFile( lockfile.toFile(), "rw" );
                 final FileChannel f = file.getChannel();
                 lock = f.tryLock();
                 if ( lock != null )
                 {
-                    LOGGER.debug( () -> "obtained file lock on file " + lockfile.getAbsolutePath() + " lock is valid=" + lock.isValid() );
+                    LOGGER.debug( () -> "obtained file lock on file " + lockfile + " lock is valid=" + lock.isValid() );
                     writeLockFileContents( file );
                 }
                 else
                 {
-                    LOGGER.debug( () -> "unable to obtain file lock on file " + lockfile.getAbsolutePath() );
+                    LOGGER.debug( () -> "unable to obtain file lock on file " + lockfile );
                 }
             }
             catch ( final Exception e )
             {
-                LOGGER.error( () -> "unable to obtain file lock on file " + lockfile.getAbsolutePath() + " due to error: " + e.getMessage() );
+                LOGGER.error( () -> "unable to obtain file lock on file " + lockfile + " due to error: " + e.getMessage() );
             }
         }
     }
@@ -94,8 +94,8 @@ class FileLocker
         {
             final Properties props = new Properties();
             props.put( "timestamp", StringUtil.toIsoDate( Instant.now() ) );
-            props.put( "applicationPath", pwmEnvironment.getApplicationPath() == null ? "n/a" : pwmEnvironment.getApplicationPath().getAbsolutePath() );
-            props.put( "configurationFile", pwmEnvironment.getConfigurationFile() == null ? "n/a" : pwmEnvironment.getConfigurationFile().getAbsolutePath() );
+            props.put( "applicationPath", pwmEnvironment.getApplicationPath() == null ? "n/a" : pwmEnvironment.getApplicationPath() );
+            props.put( "configurationFile", pwmEnvironment.getConfigurationFile() == null ? "n/a" : pwmEnvironment.getConfigurationFile() );
             final String comment = PwmConstants.PWM_APP_NAME + " file lock";
             final StringWriter stringWriter = new StringWriter();
             props.store( stringWriter, comment );
@@ -121,7 +121,7 @@ class FileLocker
                 LOGGER.error( () -> "error releasing file lock: " + e.getMessage() );
             }
 
-            LOGGER.debug( () -> "released file lock on file " + lockfile.getAbsolutePath() );
+            LOGGER.debug( () -> "released file lock on file " + lockfile );
         }
     }
 

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

@@ -52,7 +52,7 @@ public enum PwmAboutProperty
     app_instanceID( "App InstanceID", PwmApplication::getInstanceID ),
     app_trialMode( null, pwmApplication -> Boolean.toString( PwmConstants.TRIAL_MODE ) ),
     app_deployment_type( null, pwmApplication -> pwmApplication.getPwmEnvironment().getDeploymentPlatform().name() ),
-    app_applicationPath( null, pwmApplication -> pwmApplication.getPwmEnvironment().getApplicationPath().getAbsolutePath() ),
+    app_applicationPath( null, pwmApplication -> pwmApplication.getPwmEnvironment().getApplicationPath().toString() ),
     app_wordlistSize( null, pwmApplication -> Long.toString( pwmApplication.getWordlistService().size() ) ),
     app_sharedHistorySize( null, pwmApplication -> Long.toString( pwmApplication.getSharedHistoryManager().size() ) ),
     app_sharedHistoryOldestTime( null, pwmApplication -> format( pwmApplication.getSharedHistoryManager().getOldestEntryTime() ) ),

+ 19 - 16
server/src/main/java/password/pwm/PwmApplication.java

@@ -67,7 +67,9 @@ import password.pwm.util.logging.LocalDBLogger;
 import password.pwm.util.logging.PwmLogManager;
 import password.pwm.util.logging.PwmLogger;
 
-import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -157,16 +159,16 @@ public class PwmApplication
         // clear temp dir
         if ( !pwmEnvironment.isInternalRuntimeInstance() )
         {
-            final File tempFileDirectory = getTempDirectory();
+            final Path tempFileDirectory = getTempDirectory();
             try
             {
                 LOGGER.debug( sessionLabel, () -> "deleting directory (and sub-directory) contents in " + tempFileDirectory );
-                FileSystemUtility.deleteDirectoryContentsRecursively( tempFileDirectory.toPath() );
+                FileSystemUtility.deleteDirectoryContentsRecursively( tempFileDirectory );
             }
             catch ( final Exception e )
             {
                 throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_STARTUP_ERROR,
-                        "unable to clear temp file directory '" + tempFileDirectory.getAbsolutePath() + "', error: " + e.getMessage()
+                        "unable to clear temp file directory '" + tempFileDirectory + "', error: " + e.getMessage()
                 ) );
             }
         }
@@ -174,8 +176,8 @@ public class PwmApplication
         if ( getApplicationMode() != PwmApplicationMode.READ_ONLY )
         {
             LOGGER.info( sessionLabel, () -> "initializing, application mode=" + getApplicationMode()
-                    + ", applicationPath=" + ( pwmEnvironment.getApplicationPath() == null ? "null" : pwmEnvironment.getApplicationPath().getAbsolutePath() )
-                    + ", configFile=" + ( pwmEnvironment.getConfigurationFile() == null ? "null" : pwmEnvironment.getConfigurationFile().getAbsolutePath() )
+                    + ", applicationPath=" + ( pwmEnvironment.getApplicationPath() == null ? "null" : pwmEnvironment.getApplicationPath() )
+                    + ", configFile=" + ( pwmEnvironment.getConfigurationFile() == null ? "null" : pwmEnvironment.getConfigurationFile() )
             );
         }
 
@@ -768,7 +770,8 @@ public class PwmApplication
         return this.getConfig().isMultiDomain();
     }
 
-    public File getTempDirectory( ) throws PwmUnrecoverableException
+    public Path getTempDirectory( )
+            throws PwmUnrecoverableException
     {
         if ( pwmEnvironment.getApplicationPath() == null )
         {
@@ -778,21 +781,21 @@ public class PwmApplication
             );
             throw new PwmUnrecoverableException( errorInformation );
         }
-        final File tempDirectory = new File( pwmEnvironment.getApplicationPath() + File.separator + "temp" );
-        if ( !tempDirectory.exists() )
+        final Path tempDirectory = pwmEnvironment.getApplicationPath().resolve( "temp" );
+        if ( !Files.exists( tempDirectory ) )
         {
-            LOGGER.trace( () -> "preparing to create temporary directory " + tempDirectory.getAbsolutePath() );
-            if ( tempDirectory.mkdir() )
+            LOGGER.trace( () -> "preparing to create temporary directory " + tempDirectory );
+            try
             {
-                LOGGER.debug( () -> "created " + tempDirectory.getAbsolutePath() );
+                Files.createDirectories( tempDirectory );
+                LOGGER.debug( () -> "created " + tempDirectory );
             }
-            else
+            catch ( final IOException e )
             {
-                LOGGER.debug( () -> "unable to create temporary directory " + tempDirectory.getAbsolutePath() );
+                LOGGER.debug( () -> "unable to create temporary directory " + tempDirectory );
                 final ErrorInformation errorInformation = new ErrorInformation(
                         PwmError.ERROR_STARTUP_ERROR,
-                        "unable to establish create temp work directory " + tempDirectory.getAbsolutePath()
-                );
+                        "unable to establish create temp work directory " + tempDirectory );
                 throw new PwmUnrecoverableException( errorInformation );
             }
         }

+ 16 - 18
server/src/main/java/password/pwm/PwmApplicationUtil.java

@@ -45,10 +45,10 @@ import password.pwm.util.secure.PwmRandom;
 import password.pwm.util.secure.X509Utils;
 
 import java.io.ByteArrayOutputStream;
-import java.io.File;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.KeyStore;
 import java.time.Instant;
 import java.util.List;
@@ -67,7 +67,7 @@ class PwmApplicationUtil
     static LocalDB initializeLocalDB( final PwmApplication pwmApplication, final PwmEnvironment pwmEnvironment )
             throws PwmUnrecoverableException
     {
-        final File databaseDirectory;
+        final Path databaseDirectory;
 
         try
         {
@@ -181,14 +181,14 @@ class PwmApplicationUtil
                 return;
             }
 
-            final File keyStoreFile = new File( keystoreFileString.get() );
+            final Path keyStoreFile = Path.of( keystoreFileString.get() );
             final String password = pwmEnvironment.readProperty( EnvironmentProperty.AutoExportHttpsKeyStorePassword )
                     .orElseThrow( () -> new IllegalArgumentException( "keystore export property is configured, but keystore password is not specified " ) );
             final String alias = pwmEnvironment.readProperty( EnvironmentProperty.AutoExportHttpsKeyStoreAlias )
                     .orElseThrow( () -> new IllegalArgumentException( "keystore export property is configured, but keystore alias is not specified " ) );
             final KeyStore keyStore = HttpsServerCertificateManager.keyStoreForApplication( pwmApplication, new PasswordData( password ), alias );
             X509Utils.outputKeystore( keyStore, keyStoreFile, password );
-            LOGGER.info( pwmApplication.getSessionLabel(), () -> "exported application https key to keystore file " + keyStoreFile.getAbsolutePath() );
+            LOGGER.info( pwmApplication.getSessionLabel(), () -> "exported application https key to keystore file " + keyStoreFile );
         }
         catch ( final Exception e )
         {
@@ -209,17 +209,17 @@ class PwmApplicationUtil
         {
             LOGGER.trace( pwmApplication.getSessionLabel(),
                     () -> "attempting to output tomcat configuration file as configured by environment parameters to " + tomcatOutputFileStr );
-            final File tomcatOutputFile = new File( tomcatOutputFileStr.get() );
-            final File tomcatSourceFile;
+            final Path tomcatOutputFile = Path.of( tomcatOutputFileStr.get() );
+            final Path tomcatSourceFile;
             {
                 final Optional<String> tomcatSourceFileStr = pwmEnvironment.readProperty( EnvironmentProperty.AutoWriteTomcatConfSourceFile );
                 if ( tomcatSourceFileStr.isPresent() )
                 {
-                    tomcatSourceFile = new File( tomcatSourceFileStr.get() );
-                    if ( !tomcatSourceFile.exists() )
+                    tomcatSourceFile = Path.of( tomcatSourceFileStr.get() );
+                    if ( !Files.exists( tomcatSourceFile ) )
                     {
                         LOGGER.error( pwmApplication.getSessionLabel(),
-                                () -> "can not output tomcat configuration file, source file does not exist: " + tomcatSourceFile.getAbsolutePath() );
+                                () -> "can not output tomcat configuration file, source file does not exist: " + tomcatSourceFile );
                         return;
                     }
                 }
@@ -234,7 +234,7 @@ class PwmApplicationUtil
 
             try ( ByteArrayOutputStream outputContents = new ByteArrayOutputStream() )
             {
-                try ( InputStream fileInputStream = Files.newInputStream( tomcatOutputFile.toPath() ) )
+                try ( InputStream fileInputStream = Files.newInputStream( tomcatOutputFile ) )
                 {
                     ExportHttpsTomcatConfigCommand.TomcatConfigWriter.writeOutputFile(
                             pwmApplication.getConfig(),
@@ -243,22 +243,20 @@ class PwmApplicationUtil
                     );
                 }
 
-                if ( tomcatOutputFile.exists() )
+                if ( Files.exists( tomcatOutputFile ) )
                 {
-                    LOGGER.trace( pwmApplication.getSessionLabel(), () -> "deleting existing tomcat configuration file " + tomcatOutputFile.getAbsolutePath() );
-                    if ( tomcatOutputFile.delete() )
-                    {
-                        LOGGER.trace( pwmApplication.getSessionLabel(), () -> "deleted existing tomcat configuration file: " + tomcatOutputFile.getAbsolutePath() );
-                    }
+                    LOGGER.trace( pwmApplication.getSessionLabel(), () -> "deleting existing tomcat configuration file " + tomcatOutputFile );
+                    Files.delete( tomcatOutputFile );
+                    LOGGER.trace( pwmApplication.getSessionLabel(), () -> "deleted existing tomcat configuration file: " + tomcatOutputFile );
                 }
 
-                try ( OutputStream fileOutputStream = Files.newOutputStream( tomcatOutputFile.toPath() ) )
+                try ( OutputStream fileOutputStream = Files.newOutputStream( tomcatOutputFile ) )
                 {
                     fileOutputStream.write( outputContents.toByteArray() );
                 }
             }
 
-            LOGGER.info( pwmApplication.getSessionLabel(), () -> "successfully wrote tomcat configuration to file " + tomcatOutputFile.getAbsolutePath() );
+            LOGGER.info( pwmApplication.getSessionLabel(), () -> "successfully wrote tomcat configuration to file " + tomcatOutputFile );
         }
         catch ( final Exception e )
         {

+ 18 - 20
server/src/main/java/password/pwm/PwmEnvironment.java

@@ -33,7 +33,6 @@ import password.pwm.util.java.LazySupplier;
 import password.pwm.util.logging.PwmLogger;
 
 import javax.servlet.ServletContext;
-import java.io.File;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Map;
@@ -52,9 +51,9 @@ public class PwmEnvironment
     private PwmApplicationMode applicationMode = PwmApplicationMode.ERROR;
 
     private AppConfig config;
-    private File applicationPath;
+    private Path applicationPath;
     private boolean internalRuntimeInstance;
-    private File configurationFile;
+    private Path configurationFile;
     private ContextManager contextManager;
 
     private final Supplier<Map<EnvironmentProperty, String>> parameters = LazySupplier.create( this::readApplicationParams );
@@ -75,15 +74,15 @@ public class PwmEnvironment
     public void verifyIfApplicationPathIsSetProperly()
             throws PwmUnrecoverableException
     {
-        final File applicationPath = this.getApplicationPath();
+        final Path applicationPath = this.getApplicationPath();
 
         verifyApplicationPath( applicationPath );
 
         boolean applicationPathIsWebInfPath = false;
-        if ( applicationPath.getAbsolutePath().endsWith( "/WEB-INF" ) )
+        if ( applicationPath.endsWith( "WEB-INF" ) )
         {
-            final File webXmlFile = new File( applicationPath.getAbsolutePath() + File.separator + "web.xml" );
-            if ( webXmlFile.exists() )
+            final Path webXmlFilePath = applicationPath.resolve( "web.xml" );
+            if ( Files.exists( webXmlFilePath ) )
             {
                 applicationPathIsWebInfPath = true;
             }
@@ -122,7 +121,7 @@ public class PwmEnvironment
     }
 
 
-    public static void verifyApplicationPath( final File applicationPath )
+    public static void verifyApplicationPath( final Path applicationPath )
             throws PwmUnrecoverableException
     {
 
@@ -134,37 +133,37 @@ public class PwmEnvironment
             );
         }
 
-        LOGGER.trace( SESSION_LABEL, () -> "examining applicationPath of " + applicationPath.getAbsolutePath() + "" );
+        LOGGER.trace( SESSION_LABEL, () -> "examining applicationPath of " + applicationPath + "" );
 
-        if ( !applicationPath.exists() )
+        if ( !Files.exists( applicationPath ) )
         {
             throw new PwmUnrecoverableException(
                     new ErrorInformation( PwmError.ERROR_STARTUP_ERROR,
-                            "applicationPath " + applicationPath.getAbsolutePath() + " does not exist" )
+                            "applicationPath " + applicationPath + " does not exist" )
             );
         }
 
-        if ( !applicationPath.canRead() )
+        if ( !Files.isReadable( applicationPath ) )
         {
             throw new PwmUnrecoverableException(
                     new ErrorInformation( PwmError.ERROR_STARTUP_ERROR,
-                            "unable to read from applicationPath " + applicationPath.getAbsolutePath() + "" )
+                            "unable to read from applicationPath " + applicationPath + "" )
             );
         }
 
-        if ( !applicationPath.canWrite() )
+        if ( !Files.isWritable( applicationPath ) )
         {
             throw new PwmUnrecoverableException(
                     new ErrorInformation( PwmError.ERROR_STARTUP_ERROR,
-                            "unable to write to applicationPath " + applicationPath.getAbsolutePath() + "" )
+                            "unable to write to applicationPath " + applicationPath + "" )
             );
         }
 
-        final File infoFile = new File( applicationPath.getAbsolutePath() + File.separator + PwmConstants.APPLICATION_PATH_INFO_FILE );
-        LOGGER.trace( SESSION_LABEL, () -> "checking " + infoFile.getAbsolutePath() + " status" );
-        if ( infoFile.exists() )
+        final Path infoFile = applicationPath.resolve( PwmConstants.APPLICATION_PATH_INFO_FILE );
+        LOGGER.trace( SESSION_LABEL, () -> "checking " + infoFile + " status" );
+        if ( Files.exists( infoFile ) )
         {
-            final String errorMsg = "The file " + infoFile.getAbsolutePath() + " exists, and an applicationPath was not explicitly specified."
+            final String errorMsg = "The file " + infoFile + " exists, and an applicationPath was not explicitly specified."
                     + "  This happens when an applicationPath was previously configured, but is not now being specified."
                     + "  An explicit applicationPath parameter must be specified, or the file can be removed if the applicationPath"
                     + " should be changed to the default /WEB-INF directory.";
@@ -206,7 +205,6 @@ public class PwmEnvironment
 
     private Map<EnvironmentProperty, String> readApplicationParams()
     {
-        final Path applicationPath = this.applicationPath == null ? null : this.applicationPath.toPath();
         final ServletContext effectiveContext = this.contextManager == null
                 ? null
                 : this.contextManager.getServletContext();

+ 46 - 38
server/src/main/java/password/pwm/config/stored/ConfigurationFileManager.java

@@ -42,13 +42,12 @@ import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 
-import java.io.BufferedInputStream;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.math.BigInteger;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
 import java.nio.file.StandardOpenOption;
 import java.time.Instant;
@@ -65,7 +64,7 @@ public class ConfigurationFileManager
 {
     private static final PwmLogger LOGGER = PwmLogger.getLogger( ConfigurationFileManager.class.getName() );
 
-    private final File configFile;
+    private final Path configFile;
     private final String configFileChecksum;
     private final SessionLabel sessionLabel;
 
@@ -77,13 +76,28 @@ public class ConfigurationFileManager
 
     private volatile boolean saveInProgress;
 
-    public ConfigurationFileManager( final File configFile, final SessionLabel sessionLabel )
+    public ConfigurationFileManager( final Path configFile, final SessionLabel sessionLabel )
             throws PwmUnrecoverableException
     {
         this.configFile = configFile;
         this.sessionLabel = sessionLabel;
 
-        this.configFileChecksum = readFileChecksum( configFile );
+        {
+            String localChecksum = "";
+
+            try
+            {
+                localChecksum = readFileChecksum( configFile );
+            }
+            catch ( final IOException e )
+            {
+                this.configFileError = new ErrorInformation( PwmError.ERROR_INVALID_CONFIG, "i/o error: " + e.getMessage() );
+                LOGGER.warn( sessionLabel, () -> "error reading configuration file: " + e.getMessage() );
+            }
+            configFileChecksum = localChecksum;
+        }
+
+
         try
         {
             this.storedConfiguration = readStoredConfig();
@@ -129,16 +143,16 @@ public class ConfigurationFileManager
     {
         LOGGER.debug( sessionLabel, () -> "loading configuration file: " + configFile );
 
-        if ( !configFile.exists() )
+        if ( !Files.exists( configFile ) )
         {
-            LOGGER.warn( sessionLabel, () -> "configuration file '" + configFile.getAbsolutePath() + "' does not exist" );
+            LOGGER.warn( sessionLabel, () -> "configuration file '" + configFile + "' does not exist" );
             return null;
         }
 
         final StoredConfiguration storedConfiguration;
         final Instant startTime = Instant.now();
 
-        try ( InputStream theFileData = new BufferedInputStream( Files.newInputStream( configFile.toPath() ), 1024_1024 ) )
+        try ( InputStream theFileData = Files.newInputStream( configFile ) )
         {
             try
             {
@@ -170,6 +184,9 @@ public class ConfigurationFileManager
             }
 
             ConfigurationVerifier.verifyConfiguration( storedConfiguration );
+
+            final String fileSize = StringUtil.formatDiskSize( Files.size( configFile ) );
+            LOGGER.debug( sessionLabel, () -> "configuration reading/parsing of " + fileSize + " complete", TimeDuration.fromCurrent( startTime ) );
         }
         catch ( final Exception e )
         {
@@ -183,10 +200,6 @@ public class ConfigurationFileManager
             throw new PwmUnrecoverableException( errorInformation );
         }
 
-        final String fileSize = StringUtil.formatDiskSize( configFile.length() );
-        LOGGER.debug( sessionLabel, () -> "configuration reading/parsing of " + fileSize + " complete", TimeDuration.fromCurrent( startTime ) );
-
-
         final Optional<String> configIsEditable = storedConfiguration.readConfigProperty( ConfigurationProperty.CONFIG_IS_EDITABLE );
         if ( PwmConstants.TRIAL_MODE || ( configIsEditable.isPresent() && "true".equalsIgnoreCase( configIsEditable.get() ) ) )
         {
@@ -206,7 +219,7 @@ public class ConfigurationFileManager
     )
             throws IOException, PwmUnrecoverableException, PwmOperationalException
     {
-        File backupDirectory = null;
+        Path backupDirectory = null;
         int backupRotations = 0;
         if ( pwmApplication != null )
         {
@@ -214,7 +227,7 @@ public class ConfigurationFileManager
             final String backupDirSetting = domainConfig.readAppProperty( AppProperty.BACKUP_LOCATION );
             if ( backupDirSetting != null && backupDirSetting.length() > 0 )
             {
-                final File pwmPath = pwmApplication.getPwmEnvironment().getApplicationPath();
+                final Path pwmPath = pwmApplication.getPwmEnvironment().getApplicationPath();
                 backupDirectory = FileSystemUtility.figureFilepath( backupDirSetting, pwmPath );
             }
             backupRotations = Integer.parseInt( domainConfig.readAppProperty( AppProperty.BACKUP_CONFIG_COUNT ) );
@@ -240,13 +253,9 @@ public class ConfigurationFileManager
             this.storedConfiguration = modifier.newStoredConfiguration();
         }
 
-        if ( backupDirectory != null && !backupDirectory.exists() )
+        if ( backupDirectory != null && !Files.exists( backupDirectory ) )
         {
-            if ( !backupDirectory.mkdirs() )
-            {
-                throw new PwmOperationalException( new ErrorInformation( PwmError.ERROR_INTERNAL,
-                        "unable to create backup directory structure '" + backupDirectory + "'" ) );
-            }
+            Files.createDirectories( backupDirectory );
         }
 
         if ( pwmApplication != null && pwmApplication.getAuditService() != null )
@@ -307,18 +316,16 @@ public class ConfigurationFileManager
             final StoredConfiguration storedConfiguration,
             final PwmApplication pwmApplication,
             final int backupRotations,
-            final File backupDirectory
+            final Path backupDirectory
     )
             throws IOException, PwmUnrecoverableException
     {
         final Instant saveFileStartTime = Instant.now();
-        final File tempWriteFile = new File( configFile.getAbsoluteFile() + ".new" );
+        final Path tempWriteFile = FileSystemUtility.addFilenameSuffix( configFile, ".new" );
         LOGGER.info( sessionLabel, () -> "beginning write to configuration file " + tempWriteFile );
         saveInProgress = true;
 
-        try ( OutputStream fileOutputStream = Files.newOutputStream( tempWriteFile.toPath(),
-                StandardOpenOption.CREATE,
-                StandardOpenOption.TRUNCATE_EXISTING ) )
+        try ( OutputStream fileOutputStream = Files.newOutputStream( tempWriteFile ) )
         {
             StoredConfigurationFactory.output( storedConfiguration, fileOutputStream );
         }
@@ -330,25 +337,24 @@ public class ConfigurationFileManager
             pwmApplication.writeAppAttribute( AppAttribute.CONFIG_HASH, actualChecksum );
         }
 
-        LOGGER.trace( sessionLabel, () -> "renaming file " + tempWriteFile.getAbsolutePath() + " to " + configFile.getAbsolutePath() );
+        LOGGER.trace( sessionLabel, () -> "renaming file " + tempWriteFile + " to " + configFile );
         try
         {
-            Files.move( tempWriteFile.toPath(), configFile.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE );
+            Files.move( tempWriteFile, configFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE );
         }
         catch ( final Exception e )
         {
-            final String errorMsg = "unable to rename temporary save file from " + tempWriteFile.getAbsolutePath()
-                    + " to " + configFile.getAbsolutePath() + "; error: " + e.getMessage();
+            final String errorMsg = "unable to rename temporary save file from " + tempWriteFile
+                    + " to " + configFile + "; error: " + e.getMessage();
             throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_INTERNAL, errorMsg ) );
         }
 
-        if ( backupDirectory != null )
+        if ( backupDirectory != null && configFile != null && configFile.getFileName() != null )
         {
-            final String configFileName = configFile.getName();
-            final String backupFilePath = backupDirectory.getAbsolutePath() + File.separatorChar + configFileName + "-backup";
-            final File backupFile = new File( backupFilePath );
+            final String configFileName = configFile.getFileName().toString();
+            final Path backupFile = backupDirectory.resolve( configFileName + "-backup" );
             FileSystemUtility.rotateBackups( backupFile, backupRotations );
-            try ( OutputStream fileOutputStream = Files.newOutputStream( backupFile.toPath(),
+            try ( OutputStream fileOutputStream = Files.newOutputStream( backupFile,
                     StandardOpenOption.CREATE,
                     StandardOpenOption.TRUNCATE_EXISTING ) )
             {
@@ -358,19 +364,21 @@ public class ConfigurationFileManager
     }
 
     public boolean modifiedSinceLoad( )
+            throws IOException
     {
         final String currentChecksum = readFileChecksum( configFile );
         return !currentChecksum.equals( configFileChecksum );
     }
 
-    private static String readFileChecksum( final File file )
+    private static String readFileChecksum( final Path file )
+            throws IOException
     {
-        if ( !file.exists() )
+        if ( !Files.exists( file ) )
         {
             return "";
         }
 
-        return file.lastModified() + "+" + file.length();
+        return Files.getLastModifiedTime( file ) + "+" + Files.size( file );
     }
 
     public ErrorInformation getConfigFileError( )
@@ -378,7 +386,7 @@ public class ConfigurationFileManager
         return configFileError;
     }
 
-    public File getConfigFile( )
+    public Path getConfigFile( )
     {
         return configFile;
     }

+ 17 - 15
server/src/main/java/password/pwm/health/DebugOutputService.java

@@ -38,12 +38,11 @@ import password.pwm.util.logging.PwmLogLevel;
 import password.pwm.util.logging.PwmLogManager;
 import password.pwm.util.logging.PwmLogger;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.lang.management.ManagementFactory;
 import java.lang.management.ThreadInfo;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -137,8 +136,8 @@ public class DebugOutputService extends AbstractPwmService implements PwmService
         private void writeSupportZipToAppPath()
                 throws IOException, PwmUnrecoverableException
         {
-            final File appPath = getPwmApplication().getPwmEnvironment().getApplicationPath();
-            if ( !appPath.exists() )
+            final Path appPath = getPwmApplication().getPwmEnvironment().getApplicationPath();
+            if ( !Files.exists( appPath ) )
             {
                 return;
             }
@@ -146,24 +145,27 @@ public class DebugOutputService extends AbstractPwmService implements PwmService
             final int rotationCount = JavaHelper.silentParseInt( pwmApplication.getConfig().readAppProperty( AppProperty.HEALTH_SUPPORT_BUNDLE_FILE_WRITE_COUNT ), 10 );
             final DebugItemGenerator debugItemGenerator = new DebugItemGenerator( pwmApplication, getSessionLabel() );
 
-            final File supportPath = new File( appPath.getPath() + File.separator + "support" );
+            final Path supportPath = appPath.resolve( "support" );
 
-            Files.createDirectories( supportPath.toPath() );
+            Files.createDirectories( supportPath );
 
-            final File supportFile = new File ( supportPath.getPath() + File.separator + debugItemGenerator.getFilename() );
+            final Path supportFile = supportPath.resolve( debugItemGenerator.getFilename() );
 
             FileSystemUtility.rotateBackups( supportFile, rotationCount );
 
-            final File newSupportFile = new File ( supportFile.getPath() + ".new" );
-            Files.deleteIfExists( newSupportFile.toPath() );
-
-            try ( ZipOutputStream zipOutputStream = new ZipOutputStream( new FileOutputStream( newSupportFile ) ) )
+            if ( supportFile != null && supportFile.getFileName() != null && supportFile.getParent() != null )
             {
-                LOGGER.trace( getSessionLabel(), () -> "beginning periodic support bundle filesystem output" );
-                debugItemGenerator.outputZipDebugFile( zipOutputStream );
-            }
+                final Path newSupportFile = FileSystemUtility.addFilenameSuffix( supportFile, ".new" );
+                Files.deleteIfExists( newSupportFile );
 
-            Files.move( newSupportFile.toPath(), supportFile.toPath() );
+                try ( ZipOutputStream zipOutputStream = new ZipOutputStream( Files.newOutputStream( newSupportFile ) ) )
+                {
+                    LOGGER.trace( getSessionLabel(), () -> "beginning periodic support bundle filesystem output" );
+                    debugItemGenerator.outputZipDebugFile( zipOutputStream );
+                }
+
+                Files.move( newSupportFile, supportFile );
+            }
         }
     }
 

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

@@ -88,7 +88,7 @@ public class LocalDBHealthChecker implements HealthSupplier
         final long minFreeSpace = JavaHelper.silentParseLong( pwmApplication.getConfig().readAppProperty( AppProperty.HEALTH_DISK_MIN_FREE_WARNING ), 500_000_000 );
         final long freeSpace = FileSystemUtility.diskSpaceRemaining( pwmApplication.getLocalDB().getFileLocation() );
 
-        if ( freeSpace < minFreeSpace )
+        if ( freeSpace > 0 && freeSpace < minFreeSpace )
         {
             final String spaceValue = StringUtil.formatDiskSizeforDebug( freeSpace );
             return Collections.singletonList( HealthRecord.forMessage( DomainID.systemId(), HealthMessage.LocalDB_LowDiskSpace, spaceValue ) );

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

@@ -56,10 +56,8 @@ import password.pwm.util.secure.X509Utils;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpSession;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.Serializable;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.security.cert.X509Certificate;
@@ -74,29 +72,27 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
-public class ContextManager implements Serializable
+public class ContextManager
 {
-    private static final long serialVersionUID = 1L;
-
     private static final PwmLogger LOGGER = PwmLogger.forClass( ContextManager.class );
     private static final SessionLabel SESSION_LABEL = SessionLabel.CONTEXT_SESSION_LABEL;
 
     private static final TimeDuration RESTART_DELAY = TimeDuration.of( 5, TimeDuration.Unit.SECONDS );
 
-    private final transient ServletContext servletContext;
+    private final ServletContext servletContext;
     private final String contextPath;
 
-    private transient ScheduledExecutorService taskMaster;
+    private ScheduledExecutorService taskMaster;
 
-    private transient volatile PwmApplication pwmApplication;
-    private transient ConfigurationFileManager configReader;
+    private volatile PwmApplication pwmApplication;
+    private ConfigurationFileManager configReader;
     private ErrorInformation startupErrorInformation;
 
     private final AtomicInteger restartCount = new AtomicInteger( 0 );
     private TimeDuration readApplicationLockMaxWait = TimeDuration.of( 10, TimeDuration.Unit.SECONDS );
     private final AtomicBoolean restartInProgressFlag = new AtomicBoolean();
 
-    private File applicationPath;
+    private Path applicationPath;
 
     public static final String UNSPECIFIED_VALUE = "unspecified";
 
@@ -205,7 +201,7 @@ public class ContextManager implements Serializable
             return;
         }
 
-        File configurationFile = null;
+        Path configurationFile = null;
         try
         {
             configurationFile = locateConfigurationFile( applicationPath, PwmConstants.DEFAULT_CONFIG_FILE_FILENAME );
@@ -231,7 +227,7 @@ public class ContextManager implements Serializable
         }
 
         {
-            final String filename = configurationFile == null ? "null" : configurationFile.getAbsoluteFile().getAbsolutePath();
+            final String filename = configurationFile == null ? "null" : configurationFile.toString();
             LOGGER.debug( SESSION_LABEL, () -> "configuration file was loaded from " + ( filename ) );
         }
 
@@ -286,7 +282,7 @@ public class ContextManager implements Serializable
 
     private ProcessStatus initializeApplicationPath()
     {
-        EnvironmentProperty.readApplicationPath( this.servletContext ).ifPresent( appPath -> this.applicationPath = appPath.toFile() );
+        this.applicationPath = EnvironmentProperty.readApplicationPath( this.servletContext ).orElse( null );
 
         if ( this.applicationPath == null )
         {
@@ -294,7 +290,7 @@ public class ContextManager implements Serializable
             return ProcessStatus.Halt;
         }
 
-        if ( !this.applicationPath.exists() )
+        if ( !Files.exists( this.applicationPath ) )
         {
             startupErrorInformation = new ErrorInformation( PwmError.ERROR_ENVIRONMENT_ERROR, "specified application path does not exist" );
             return ProcessStatus.Halt;
@@ -425,10 +421,17 @@ public class ContextManager implements Serializable
         {
             if ( configReader != null )
             {
-                if ( configReader.modifiedSinceLoad() )
+                try
+                {
+                    if ( configReader.modifiedSinceLoad() )
+                    {
+                        LOGGER.info( SESSION_LABEL, () -> "configuration file modification has been detected" );
+                        requestPwmApplicationRestart();
+                    }
+                }
+                catch ( final IOException e )
                 {
-                    LOGGER.info( SESSION_LABEL, () -> "configuration file modification has been detected" );
-                    requestPwmApplicationRestart();
+                    LOGGER.warn( SESSION_LABEL, () -> "error checking for config file modifications: " + e.getMessage() );
                 }
             }
         }
@@ -436,7 +439,7 @@ public class ContextManager implements Serializable
 
     private class SilentPropertiesFileWatcher implements Runnable
     {
-        private final File silentPropertiesFile;
+        private final Path silentPropertiesFile;
 
         SilentPropertiesFileWatcher()
         {
@@ -448,32 +451,32 @@ public class ContextManager implements Serializable
         {
             if ( pwmApplication == null || pwmApplication.getApplicationMode() == PwmApplicationMode.NEW )
             {
-                if ( silentPropertiesFile.exists() )
+                if ( Files.exists( silentPropertiesFile ) )
                 {
                     boolean success = false;
-                    LOGGER.info( SESSION_LABEL, () -> "file " + silentPropertiesFile.getAbsolutePath() + " has appeared, will import as configuration" );
+                    LOGGER.info( SESSION_LABEL, () -> "file " + silentPropertiesFile + " has appeared, will import as configuration" );
                     try
                     {
                         final PropertyConfigurationImporter importer = new PropertyConfigurationImporter();
 
                         final StoredConfiguration storedConfiguration;
-                        try ( InputStream fileInputStream = Files.newInputStream( silentPropertiesFile.toPath() ) )
+                        try ( InputStream fileInputStream = Files.newInputStream( silentPropertiesFile ) )
                         {
                             storedConfiguration = importer.readConfiguration( fileInputStream );
                         }
 
                         configReader.saveConfiguration( storedConfiguration, pwmApplication );
-                        LOGGER.info( SESSION_LABEL, () -> "file " + silentPropertiesFile.getAbsolutePath() + " has been successfully imported and saved as configuration file" );
+                        LOGGER.info( SESSION_LABEL, () -> "file " + silentPropertiesFile + " has been successfully imported and saved as configuration file" );
                         requestPwmApplicationRestart();
                         success = true;
                     }
                     catch ( final Exception e )
                     {
-                        LOGGER.error( SESSION_LABEL, () -> "error importing " + silentPropertiesFile.getAbsolutePath() + ", error: " + e.getMessage() );
+                        LOGGER.error( SESSION_LABEL, () -> "error importing " + silentPropertiesFile + ", error: " + e.getMessage() );
                     }
 
                     final String appendValue = success ? ".imported" : ".error";
-                    final Path source = silentPropertiesFile.toPath();
+                    final Path source = silentPropertiesFile;
                     final Path dest = source.resolveSibling( "silent.properties" + appendValue );
 
                     try
@@ -583,19 +586,19 @@ public class ContextManager implements Serializable
         return servletContext;
     }
 
-    private File locateConfigurationFile( final File applicationPath, final String filename )
+    private Path locateConfigurationFile( final Path applicationPath, final String filename )
     {
-        return new File( applicationPath.getAbsolutePath() + File.separator + filename );
+        return applicationPath.resolve( filename );
     }
 
-    public Optional<File> locateWebInfFilePath( )
+    public Optional<Path> locateWebInfFilePath( )
     {
         final String realPath = servletContext.getRealPath( "/WEB-INF" );
 
         if ( realPath != null )
         {
-            final File servletPath = new File( realPath );
-            if ( servletPath.exists() )
+            final Path servletPath = Path.of( realPath );
+            if ( Files.exists( servletPath ) )
             {
                 return Optional.of( servletPath );
             }

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

@@ -425,7 +425,9 @@ public class AppDashboardData implements Serializable
                     ? notApplicable
                     : pwmDomain.getPwmApplication().getLocalDB().getFileLocation() == null
                             ? notApplicable
-                            : StringUtil.formatDiskSize( FileSystemUtility.diskSpaceRemaining( pwmDomain.getPwmApplication().getLocalDB().getFileLocation() ) );
+                            : StringUtil.formatDiskSize( FileSystemUtility.diskSpaceRemaining(
+                                    pwmDomain.getPwmApplication().getLocalDB().getFileLocation() ) );
+
             localDbInfo.add( new DisplayElement(
                     "localDbFreeSpace",
                     DisplayElement.Type.string,

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/admin/system/ConfigManagerLocalDBServlet.java

@@ -54,10 +54,10 @@ import javax.servlet.ServletException;
 import javax.servlet.annotation.WebServlet;
 import javax.servlet.http.HttpServletRequest;
 import java.io.BufferedOutputStream;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Collection;
 import java.util.Collections;
@@ -187,7 +187,7 @@ public class ConfigManagerLocalDBServlet extends AbstractPwmServlet
             try ( InputStream inputStream = optionalFileUpload.get() )
             {
                 localDB = pwmApplication.getLocalDB();
-                final File localDBLocation = pwmApplication.getLocalDB().getFileLocation();
+                final Path localDBLocation = pwmApplication.getLocalDB().getFileLocation();
                 final DomainConfig domainConfig = pwmDomain.getConfig();
                 contextManager.shutdown();
 

+ 2 - 2
server/src/main/java/password/pwm/http/servlet/admin/system/ConfigManagerServlet.java

@@ -192,8 +192,8 @@ public class ConfigManagerServlet extends AbstractPwmServlet
     {
         final ConfigurationFileManager configurationFileManager = pwmRequest.getContextManager().getConfigReader();
         pwmRequest.setAttribute( PwmRequestAttribute.PageTitle, LocaleHelper.getLocalizedMessage( Config.Title_ConfigManager, pwmRequest ) );
-        pwmRequest.setAttribute( PwmRequestAttribute.ApplicationPath, pwmRequest.getPwmApplication().getPwmEnvironment().getApplicationPath().getAbsolutePath() );
-        pwmRequest.setAttribute( PwmRequestAttribute.ConfigFilename, configurationFileManager.getConfigFile().getAbsolutePath() );
+        pwmRequest.setAttribute( PwmRequestAttribute.ApplicationPath, pwmRequest.getPwmApplication().getPwmEnvironment().getApplicationPath().toString() );
+        pwmRequest.setAttribute( PwmRequestAttribute.ConfigFilename, configurationFileManager.getConfigFile().toString() );
         {
             final Instant lastModifyTime = configurationFileManager.getStoredConfiguration().modifyTime();
             final String output = lastModifyTime == null

+ 2 - 0
server/src/main/java/password/pwm/http/servlet/resource/CacheKey.java

@@ -22,6 +22,7 @@ package password.pwm.http.servlet.resource;
 
 import lombok.Value;
 
+import java.io.IOException;
 import java.io.Serializable;
 import java.time.Instant;
 import java.util.Objects;
@@ -34,6 +35,7 @@ final class CacheKey implements Serializable
     private final Instant fileModificationTimestamp;
 
     static CacheKey createCacheKey( final FileResource file, final boolean acceptsGzip )
+            throws IOException
     {
         Objects.requireNonNull( file );
         return new CacheKey( file.getName(), acceptsGzip, file.lastModified() );

+ 4 - 2
server/src/main/java/password/pwm/http/servlet/resource/FileResource.java

@@ -28,9 +28,11 @@ interface FileResource
 {
     InputStream getInputStream( ) throws IOException;
 
-    long length( );
+    long length( )
+            throws IOException;
 
-    Instant lastModified( );
+    Instant lastModified( )
+            throws IOException;
 
     String getName( );
 }

+ 10 - 7
server/src/main/java/password/pwm/http/servlet/resource/RealFileResource.java

@@ -20,17 +20,17 @@
 
 package password.pwm.http.servlet.resource;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.time.Instant;
 
 class RealFileResource implements FileResource
 {
-    private final File realFile;
+    private final Path realFile;
 
-    RealFileResource( final File realFile )
+    RealFileResource( final Path realFile )
     {
         this.realFile = realFile;
     }
@@ -38,24 +38,27 @@ class RealFileResource implements FileResource
     @Override
     public InputStream getInputStream( ) throws IOException
     {
-        return Files.newInputStream( realFile.toPath() );
+        return Files.newInputStream( realFile );
     }
 
     @Override
     public long length( )
+            throws IOException
     {
-        return realFile.length();
+        return Files.size( realFile );
     }
 
     @Override
     public Instant lastModified( )
+            throws IOException
     {
-        return Instant.ofEpochMilli( realFile.lastModified() );
+        return Files.getLastModifiedTime( realFile ).toInstant();
     }
 
     @Override
     public String getName( )
     {
-        return realFile.getAbsolutePath();
+        final Path fileName = realFile.getFileName();
+        return fileName == null ? "" : fileName.toString();
     }
 }

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

@@ -36,9 +36,10 @@ import password.pwm.util.logging.PwmLogger;
 
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Arrays;
 import java.util.Collection;
@@ -340,8 +341,8 @@ class ResourceFileRequest
             if ( effectiveUri.startsWith( ResourceFileServlet.WEBJAR_BASE_URL_PATH ) )
             {
                 // This allows us to override a webjar file, if needed.  Mostly helpful during development.
-                final File file = new File( servletContext.getRealPath( effectiveUri ) );
-                if ( file.exists() )
+                final Path file = Path.of( servletContext.getRealPath( effectiveUri ) );
+                if ( Files.exists( file ) )
                 {
                     return Optional.of( new RealFileResource( file ) );
                 }
@@ -414,9 +415,9 @@ class ResourceFileRequest
 
             // convert to file.
             final String filePath = servletContext.getRealPath( effectiveUri );
-            final File file = new File( filePath );
+            final Path file = Path.of( filePath );
 
-            if ( file.exists() )
+            if ( Files.exists( file ) )
             {
                 verifyPath( file, servletContext );
 
@@ -427,31 +428,21 @@ class ResourceFileRequest
         }
 
         private void verifyPath(
-                final File file,
+                final Path file,
                 final ServletContext servletContext
         )
                 throws PwmUnrecoverableException
         {
             // figure top-most path allowed by request
             final String parentDirectoryPath = servletContext.getRealPath( ResourceFileServlet.RESOURCE_PATH );
-            final File parentDirectory = new File( parentDirectoryPath );
+            final Path parentDirectory = Path.of( parentDirectoryPath );
 
+            if ( file.startsWith( parentDirectory ) )
             {
-                //verify the requested page is a child of the servlet resource path.
-                int recursions = 0;
-                File recurseFile = file.getParentFile();
-                while ( recurseFile != null && recursions < 100 )
-                {
-                    if ( parentDirectory.equals( recurseFile ) )
-                    {
-                        return;
-                    }
-                    recurseFile = recurseFile.getParentFile();
-                    recursions++;
-                }
+                return;
             }
 
-            LOGGER.warn( () -> "attempt to access file outside of servlet path " + file.getAbsolutePath() );
+            LOGGER.warn( () -> "attempt to access file outside of servlet path " + file );
             throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_SERVICE_NOT_AVAILABLE, "illegal file path request" ) );
         }
     }

+ 39 - 33
server/src/main/java/password/pwm/http/servlet/resource/ResourceServletConfiguration.java

@@ -21,15 +21,14 @@
 package password.pwm.http.servlet.resource;
 
 import lombok.Value;
-import org.apache.commons.io.FileUtils;
 import password.pwm.AppProperty;
 import password.pwm.PwmDomain;
 import password.pwm.bean.SessionLabel;
 import password.pwm.config.DomainConfig;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.value.FileValue;
-import password.pwm.util.java.CollectionUtil;
 import password.pwm.data.ImmutableByteArray;
+import password.pwm.util.java.CollectionUtil;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.json.JsonFactory;
@@ -38,6 +37,7 @@ import password.pwm.util.logging.PwmLogger;
 import java.io.File;
 import java.io.IOException;
 import java.io.Serializable;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Collections;
 import java.util.HashMap;
@@ -102,9 +102,10 @@ class ResourceServletConfiguration
         customFileBundle = makeCustomFileBundle( sessionLabel, domainConfig );
     }
 
-    private Map<String, FileResource> makeCustomFileBundle(
+    private static Map<String, FileResource> makeCustomFileBundle(
             final SessionLabel sessionLabel,
-            final DomainConfig domainConfig )
+            final DomainConfig domainConfig
+    )
     {
         final Map<String, FileResource> customFileBundle = new HashMap<>();
         final Map<FileValue.FileInformation, FileValue.FileContent> files = domainConfig.readSettingAsFile( PwmSetting.DISPLAY_CUSTOM_RESOURCE_BUNDLE );
@@ -113,14 +114,11 @@ class ResourceServletConfiguration
             final Map.Entry<FileValue.FileInformation, FileValue.FileContent> entry = files.entrySet().iterator().next();
             final FileValue.FileInformation fileInformation = entry.getKey();
             final FileValue.FileContent fileContent = entry.getValue();
-            LOGGER.debug( sessionLabel, () -> "examining configured zip file resource for items name=" + fileInformation.getFilename() + ", size=" + fileContent.size() );
+            LOGGER.debug( sessionLabel, () -> "examining configured zip file resource for items name=" + fileInformation.getFilename()
+                    + ", size=" + fileContent.size() );
 
             try
             {
-                final byte[] bytes = entry.getValue().getContents().copyOf();
-                final String path = "/tmp/" + domainConfig.getDomainID().stringValue();
-                FileUtils.writeByteArrayToFile( new File( path ), bytes );
-
                 final Map<String, FileResource> customFiles = makeMemoryFileMapFromZipInput( sessionLabel, fileContent.getContents() );
                 customFileBundle.putAll( customFiles );
             }
@@ -132,43 +130,51 @@ class ResourceServletConfiguration
         return Collections.unmodifiableMap( customFileBundle );
     }
 
-    private Map<String, ZipFile> makeZipResourcesFromConfig(
+    private static Map<String, ZipFile> makeZipResourcesFromConfig(
             final SessionLabel sessionLabel,
             final PwmDomain pwmDomain,
             final DomainConfig domainConfig )
     {
-        final Map<String, ZipFile> zipResources = new HashMap<>();
         final String zipFileResourceParam = domainConfig.getAppConfig().readAppProperty( AppProperty.HTTP_RESOURCES_ZIP_FILES );
-        if ( StringUtil.notEmpty( zipFileResourceParam ) )
+        if ( StringUtil.isEmpty( zipFileResourceParam ) )
         {
-            final List<ConfiguredZipFileResource> configuredZipFileResources = JsonFactory.get().deserializeList( zipFileResourceParam, ConfiguredZipFileResource.class );
-            for ( final ConfiguredZipFileResource configuredZipFileResource : configuredZipFileResources )
+            return Collections.emptyMap();
+        }
+
+        final List<ConfiguredZipFileResource> configuredZipFileResources = JsonFactory.get().deserializeList(
+                zipFileResourceParam,
+                ConfiguredZipFileResource.class );
+
+        final Map<String, ZipFile> zipResources = new HashMap<>();
+        for ( final ConfiguredZipFileResource configuredZipFileResource : configuredZipFileResources )
+        {
+            final Optional<Path> webInfPath = pwmDomain.getPwmApplication().getPwmEnvironment().getContextManager().locateWebInfFilePath();
+            if ( webInfPath.isPresent() )
             {
-                final Optional<File> webInfPath = pwmDomain.getPwmApplication().getPwmEnvironment().getContextManager().locateWebInfFilePath();
-                if ( webInfPath.isPresent() )
+                try
                 {
-                    try
-                    {
-                        final File zipFileFile = new File(
-                                webInfPath.get().getParentFile() + "/"
-                                        + ResourceFileServlet.RESOURCE_PATH
-                                        + configuredZipFileResource.getZipFile()
-                        );
-                        final ZipFile zipFile = new ZipFile( zipFileFile );
-                        zipResources.put( ResourceFileServlet.RESOURCE_PATH + configuredZipFileResource.getUrl(), zipFile );
-                        LOGGER.debug( sessionLabel, () -> "registered resource-zip file " + configuredZipFileResource.getZipFile() + " at path " + zipFileFile.getAbsolutePath() );
-                    }
-                    catch ( final IOException e )
-                    {
-                        LOGGER.warn( sessionLabel, () -> "unable to resource-zip file " + configuredZipFileResource + ", error: " + e.getMessage() );
-                    }
+                    final File zipFileFile = new File(
+                            webInfPath.get().toFile().getParentFile() + "/"
+                                    + ResourceFileServlet.RESOURCE_PATH
+                                    + configuredZipFileResource.getZipFile()
+                    );
+                    final ZipFile zipFile = new ZipFile( zipFileFile );
+                    zipResources.put( ResourceFileServlet.RESOURCE_PATH + configuredZipFileResource.getUrl(), zipFile );
+                    LOGGER.debug( sessionLabel, () -> "registered resource-zip file " + configuredZipFileResource.getZipFile()
+                            + " at path " + zipFileFile.getAbsolutePath() );
                 }
-                else
+                catch ( final IOException e )
                 {
-                    LOGGER.error( sessionLabel, () -> "can't register resource-zip file " + configuredZipFileResource.getZipFile() + " because WEB-INF path is unknown" );
+                    LOGGER.warn( sessionLabel, () -> "unable to resource-zip file " + configuredZipFileResource + ", error: " + e.getMessage() );
                 }
             }
+            else
+            {
+                LOGGER.error( sessionLabel, () -> "can't register resource-zip file " + configuredZipFileResource.getZipFile()
+                        + " because WEB-INF path is unknown" );
+            }
         }
+
         return Collections.unmodifiableMap( zipResources );
     }
 

+ 23 - 24
server/src/main/java/password/pwm/http/servlet/resource/ResourceServletService.java

@@ -33,9 +33,9 @@ import password.pwm.health.HealthRecord;
 import password.pwm.http.PwmRequest;
 import password.pwm.svc.AbstractPwmService;
 import password.pwm.svc.PwmService;
+import password.pwm.util.Percent;
 import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.java.JavaHelper;
-import password.pwm.util.Percent;
 import password.pwm.util.java.StatisticAverageBundle;
 import password.pwm.util.java.StatisticCounterBundle;
 import password.pwm.util.java.TimeDuration;
@@ -43,17 +43,17 @@ import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.secure.PwmHashAlgorithm;
 
 import javax.servlet.ServletContext;
-import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.DigestOutputStream;
 import java.time.Instant;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -299,37 +299,36 @@ public class ResourceServletService extends AbstractPwmService implements PwmSer
 
     private static void checksumResourceFilePath( final PwmDomain pwmDomain, final DigestOutputStream checksumStream )
     {
-        if ( pwmDomain.getPwmApplication().getPwmEnvironment().getContextManager() != null )
+        if ( pwmDomain.getPwmApplication().getPwmEnvironment().getContextManager() == null )
+        {
+            return;
+        }
+
+        pwmDomain.getPwmApplication().getPwmEnvironment().getContextManager().locateWebInfFilePath().ifPresent( webInfPath ->
         {
-            try
+            final Path basePath = webInfPath.getParent();
+            if ( basePath != null && Files.exists( basePath ) )
             {
-                final Optional<File> webInfPath = pwmDomain.getPwmApplication().getPwmEnvironment().getContextManager().locateWebInfFilePath();
-                if ( webInfPath.isPresent() && webInfPath.get().exists() )
+                final Path resourcePath = basePath.resolve( "public" ).resolve( "resources" );
+                if ( Files.exists( resourcePath ) )
                 {
-                    final File basePath = webInfPath.get().getParentFile();
-                    if ( basePath != null && basePath.exists() )
+                    final List<FileSystemUtility.FileSummaryInformation> fileSummaryInformations =
+                            FileSystemUtility.readFileInformation( Collections.singletonList( resourcePath ) );
                     {
-                        final File resourcePath = new File( basePath.getAbsolutePath() + File.separator + "public" + File.separator + "resources" );
-                        if ( resourcePath.exists() )
+                        for ( final FileSystemUtility.FileSummaryInformation fileSummaryInformation : fileSummaryInformations  )
                         {
-                            final Iterator<FileSystemUtility.FileSummaryInformation> iter =
-                                    FileSystemUtility.readFileInformation( Collections.singletonList( resourcePath ) );
+                            try
                             {
-                                while ( iter.hasNext()  )
-                                {
-                                    final FileSystemUtility.FileSummaryInformation fileSummaryInformation = iter.next();
-                                    checksumStream.write( fileSummaryInformation.getSha512Hash().getBytes( StandardCharsets.UTF_8 ) );
-                                }
-
+                                checksumStream.write( fileSummaryInformation.getSha512Hash().getBytes( StandardCharsets.UTF_8 ) );
+                            }
+                            catch ( final Exception e )
+                            {
+                                LOGGER.error( () -> "unable to generate resource path nonce: " + e.getMessage() );
                             }
                         }
                     }
                 }
             }
-            catch ( final Exception e )
-            {
-                LOGGER.error( () -> "unable to generate resource path nonce: " + e.getMessage() );
-            }
-        }
+        } );
     }
 }

+ 33 - 29
server/src/main/java/password/pwm/svc/db/JDBCDriverLoader.java

@@ -25,15 +25,14 @@ import org.xeustechnologies.jcl.JarClassLoader;
 import org.xeustechnologies.jcl.JclObjectFactory;
 import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
+import password.pwm.data.ImmutableByteArray;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.data.ImmutableByteArray;
 import password.pwm.util.java.JavaHelper;
 import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.lang.reflect.Constructor;
@@ -41,6 +40,7 @@ import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.sql.Driver;
@@ -207,7 +207,7 @@ public class JDBCDriverLoader
 
         private static final PwmLogger LOGGER = PwmLogger.forClass( TempFileDriverLoader.class, true );
 
-        private File tempFile;
+        private Path tempFile;
 
         @Override
 
@@ -232,26 +232,25 @@ public class JDBCDriverLoader
                 if ( tempFile == null )
                 {
                     final String prefixName = PwmConstants.PWM_APP_NAME.toLowerCase() + "_jdbcJar_";
-                    tempFile = File.createTempFile( prefixName, "jar" );
-                    LOGGER.trace( () -> "created temp file " + tempFile.getAbsolutePath() );
+                    tempFile = Files.createTempFile( pwmApplication.getTempDirectory(), prefixName, "jar" );
+                    LOGGER.trace( () -> "created temp file " + tempFile );
                 }
 
-                try ( OutputStream fos = Files.newOutputStream( tempFile.toPath() ) )
+                try ( OutputStream outputStream = Files.newOutputStream( tempFile ) )
                 {
-                    JavaHelper.copy( jdbcDriverBytes.newByteArrayInputStream(), fos );
-                    fos.close();
+                    JavaHelper.copy( jdbcDriverBytes.newByteArrayInputStream(), outputStream );
                 }
 
                 final URLClassLoader urlClassLoader = new URLClassLoader(
                         new URL[]
                                 {
-                                        tempFile.toURI().toURL(),
+                                        tempFile.toUri().toURL(),
                                 },
                         this.getClass().getClassLoader()
                 );
 
                 //Create object of loaded class
-                final Class jdbcDriverClass = urlClassLoader.loadClass( jdbcClassName );
+                final Class<?> jdbcDriverClass = urlClassLoader.loadClass( jdbcClassName );
                 final Driver driver = ( Driver ) jdbcDriverClass.getDeclaredConstructor().newInstance();
 
                 LOGGER.debug( () -> "successfully loaded JDBC database driver '" + jdbcClassName + "' from application configuration" );
@@ -271,9 +270,16 @@ public class JDBCDriverLoader
         {
             if ( tempFile != null )
             {
-                if ( tempFile.delete() )
+                try
                 {
-                    LOGGER.trace( () -> "removed temporary file " + tempFile.getAbsolutePath() );
+                    if ( Files.deleteIfExists( tempFile ) )
+                    {
+                        LOGGER.trace( () -> "removed temporary file " + tempFile );
+                    }
+                }
+                catch ( final IOException e )
+                {
+                    LOGGER.trace( () -> "error removing temporary file " + tempFile + ", error: " + e.getMessage(), e );
                 }
             }
             tempFile = null;
@@ -285,7 +291,7 @@ public class JDBCDriverLoader
 
         private static final PwmLogger LOGGER = PwmLogger.forClass( AppPathDriverLoader.class, true );
 
-        // static ccache of classloader to prevent classloader memory leak
+        // static cache of classloader to prevent classloader memory leak
         private static Map<String, ClassLoader> driverCache = new ConcurrentHashMap<>();
 
 
@@ -327,11 +333,11 @@ public class JDBCDriverLoader
                 try
                 {
                     LOGGER.debug( () -> "loading JDBC database driver stored in configuration" );
-                    final File tempFile = createOrGetTempJarFile( pwmApplication, jdbcDriverBytes );
+                    final Path tempFile = createOrGetTempJarFile( pwmApplication, jdbcDriverBytes );
                     urlClassLoader = new URLClassLoader(
                             new URL[]
                                     {
-                                            tempFile.toURI().toURL(),
+                                            tempFile.toUri().toURL(),
                                     },
                             this.getClass().getClassLoader()
                     );
@@ -348,7 +354,7 @@ public class JDBCDriverLoader
             try
             {
                 //Create object of loaded class
-                final Class jdbcDriverClass = urlClassLoader.loadClass( jdbcClassName );
+                final Class<?> jdbcDriverClass = urlClassLoader.loadClass( jdbcClassName );
                 final Driver driver = ( Driver ) jdbcDriverClass.getDeclaredConstructor().newInstance();
                 LOGGER.debug( () -> "successfully loaded JDBC database driver '" + jdbcClassName + "' from application configuration" );
                 return driver;
@@ -366,35 +372,33 @@ public class JDBCDriverLoader
         {
         }
 
-        File createOrGetTempJarFile( final PwmApplication pwmApplication, final ImmutableByteArray jarBytes ) throws PwmUnrecoverableException, IOException
+        Path createOrGetTempJarFile( final PwmApplication pwmApplication, final ImmutableByteArray jarBytes )
+                throws PwmUnrecoverableException, IOException
         {
-            final File file = pwmApplication.getTempDirectory();
+            final Path file = pwmApplication.getTempDirectory();
             final String jarHash = pwmApplication.getSecureService().hash( jarBytes.newByteArrayInputStream() );
             final String tempFileName = "jar-" + jarHash + ".jar";
-            final File tempFile = new File( file.getAbsolutePath() + File.separator + tempFileName );
-            if ( tempFile.exists() )
+            final Path tempFile = file.resolve( tempFileName );
+            if ( Files.exists( tempFile ) )
             {
                 final String fileHash = pwmApplication.getSecureService().hash( tempFile );
                 if ( !jarHash.equals( fileHash ) )
                 {
-                    LOGGER.debug( () -> "existing temp jar file " + tempFile.getAbsolutePath() + " has wrong contents, will delete" );
-                    if ( !tempFile.delete() )
-                    {
-                        throw new IOException( "unable to delete temp file " + jarHash );
-                    }
+                    LOGGER.debug( () -> "existing temp jar file " + tempFile + " has wrong contents, will delete" );
+                    Files.delete( tempFile );
                 }
             }
-            if ( !tempFile.exists() )
+            if ( !Files.exists( tempFile ) )
             {
-                LOGGER.debug( () -> "creating temp jar file " + tempFile.getAbsolutePath() );
-                try ( OutputStream fos = Files.newOutputStream( tempFile.toPath() ) )
+                LOGGER.debug( () -> "creating temp jar file " + tempFile );
+                try ( OutputStream fos = Files.newOutputStream( tempFile ) )
                 {
                     JavaHelper.copy( jarBytes.newByteArrayInputStream(), fos );
                 }
             }
             else
             {
-                LOGGER.trace( () -> "reusing existing temp jar file " + tempFile.getAbsolutePath() );
+                LOGGER.trace( () -> "reusing existing temp jar file " + tempFile );
             }
 
             return tempFile;

+ 4 - 3
server/src/main/java/password/pwm/svc/secure/AbstractSecureService.java

@@ -44,9 +44,10 @@ import password.pwm.util.secure.PwmRandom;
 import password.pwm.util.secure.PwmSecurityKey;
 import password.pwm.util.secure.SecureEngine;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.DigestInputStream;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -308,12 +309,12 @@ public abstract class AbstractSecureService extends AbstractPwmService implement
 
     @Override
     public String hash(
-            final File file
+            final Path file
     )
             throws IOException, PwmUnrecoverableException
     {
         stats.increment( StatKey.hashOperations );
-        stats.increment( StatKey.hashBytes, file.length() );
+        stats.increment( StatKey.hashBytes, Files.size( file ) );
         return SecureEngine.hash( file, defaultHashAlgorithm );
     }
 

+ 2 - 2
server/src/main/java/password/pwm/svc/secure/SecureService.java

@@ -24,9 +24,9 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.secure.PwmHashAlgorithm;
 import password.pwm.util.secure.PwmSecurityKey;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Path;
 
 public interface SecureService
 {
@@ -49,7 +49,7 @@ public interface SecureService
             throws PwmUnrecoverableException;
 
     String hash(
-            File file
+            Path file
     )
             throws IOException, PwmUnrecoverableException;
 

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

@@ -33,9 +33,9 @@ import password.pwm.util.cli.commands.ExportHttpsTomcatConfigCommand;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.secure.HttpsServerCertificateManager;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.KeyStore;
 import java.util.Properties;
 
@@ -55,10 +55,10 @@ public class OnejarHelper
     )
             throws Exception
     {
-        final PwmApplication pwmApplication = makePwmApplication( new File( applicationPath ) );
+        final PwmApplication pwmApplication = makePwmApplication( Path.of( applicationPath ) );
         try
         {
-            exportKeystore( pwmApplication, password, alias, new File( keystorePath ) );
+            exportKeystore( pwmApplication, password, alias, Path.of( keystorePath ) );
             return createProperties( pwmApplication.getConfig() );
         }
         finally
@@ -92,7 +92,7 @@ public class OnejarHelper
             final PwmApplication pwmApplication,
             final String password,
             final String alias,
-            final File exportFile
+            final Path exportFile
     )
             throws Exception
     {
@@ -100,16 +100,16 @@ public class OnejarHelper
                 pwmApplication,
                 new PasswordData( password ),
                 alias );
-        try ( OutputStream outputStream = new FileOutputStream( exportFile ) )
+        try ( OutputStream outputStream = Files.newOutputStream( exportFile ) )
         {
             keyStore.store( outputStream, password.toCharArray() );
         }
     }
 
-    private static PwmApplication makePwmApplication( final File applicationPath )
+    private static PwmApplication makePwmApplication( final Path applicationPath )
             throws Exception
     {
-        final File configFile = new File( applicationPath + File.separator + PwmConstants.DEFAULT_CONFIG_FILE_FILENAME );
+        final Path configFile = applicationPath.resolve( PwmConstants.DEFAULT_CONFIG_FILE_FILENAME );
         final ConfigurationFileManager configReader = new ConfigurationFileManager( configFile, SessionLabel.ONEJAR_LABEL );
         final AppConfig config = configReader.getConfiguration();
         final PwmEnvironment pwmEnvironment = PwmEnvironment.builder()

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

@@ -27,8 +27,8 @@ import password.pwm.config.AppConfig;
 import password.pwm.config.stored.ConfigurationFileManager;
 import password.pwm.util.localdb.LocalDB;
 
-import java.io.File;
 import java.io.Writer;
+import java.nio.file.Path;
 import java.util.Map;
 
 @Value
@@ -36,9 +36,9 @@ import java.util.Map;
 public class CliEnvironment
 {
     final ConfigurationFileManager configurationFileManager;
-    final File configurationFile;
+    final Path configurationFile;
     final AppConfig config;
-    final File applicationPath;
+    final Path applicationPath;
     final PwmApplication pwmApplication;
     final LocalDB localDB;
     final Writer debugWriter;

+ 21 - 21
server/src/main/java/password/pwm/util/cli/MainClass.java

@@ -67,9 +67,9 @@ import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBFactory;
 import password.pwm.util.logging.PwmLogger;
 
-import java.io.File;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -179,11 +179,11 @@ public class MainClass
     {
 
         final Map<String, Object> options = parseCommandOptions( parameters, args );
-        final File applicationPath = figureApplicationPath( mainOptions );
-        out( "applicationPath=" + applicationPath.getAbsolutePath() );
+        final Path applicationPath = figureApplicationPath( mainOptions );
+        out( "applicationPath=" + applicationPath );
         PwmEnvironment.verifyApplicationPath( applicationPath );
 
-        final File configurationFile = locateConfigurationFile( applicationPath );
+        final Path configurationFile = locateConfigurationFile( applicationPath );
 
         final ConfigurationFileManager configReader = loadConfiguration( configurationFile );
         final AppConfig config = configReader.getConfiguration();
@@ -250,10 +250,10 @@ public class MainClass
                         case NEW_FILE:
                             try
                             {
-                                final File theFile = new File( argument );
-                                if ( theFile.exists() )
+                                final Path theFile = Path.of( argument );
+                                if ( Files.exists( theFile ) )
                                 {
-                                    throw new CliException( "file for option '" + option.getName() + "' at '" + theFile.getAbsolutePath() + "' already exists" );
+                                    throw new CliException( "file for option '" + option.getName() + "' at '" + theFile + "' already exists" );
                                 }
                                 returnObj.put( option.getName(), theFile );
                             }
@@ -270,10 +270,10 @@ public class MainClass
                         case EXISTING_FILE:
                             try
                             {
-                                final File theFile = new File( argument );
-                                if ( !theFile.exists() )
+                                final Path theFile = Path.of( argument );
+                                if ( !Files.exists( theFile ) )
                                 {
-                                    throw new CliException( "file for option '" + option.getName() + "' at '" + theFile.getAbsolutePath() + "' does not exist" );
+                                    throw new CliException( "file for option '" + option.getName() + "' at '" + theFile + "' does not exist" );
                                 }
                                 returnObj.put( option.getName(), theFile );
                             }
@@ -402,17 +402,17 @@ public class MainClass
     private static LocalDB loadPwmDB(
             final AppConfig config,
             final boolean readonly,
-            final File applicationPath
+            final Path applicationPath
     )
             throws Exception
     {
-        final File databaseDirectory;
+        final Path databaseDirectory;
         final String pwmDBLocationSetting = config.readAppProperty( AppProperty.LOCALDB_LOCATION );
         databaseDirectory = FileSystemUtility.figureFilepath( pwmDBLocationSetting, applicationPath );
         return LocalDBFactory.getInstance( databaseDirectory, readonly, null, config );
     }
 
-    private static ConfigurationFileManager loadConfiguration( final File configurationFile ) throws Exception
+    private static ConfigurationFileManager loadConfiguration( final Path configurationFile ) throws Exception
     {
         final ConfigurationFileManager reader = new ConfigurationFileManager( configurationFile, SessionLabel.CLI_SESSION_LABEL );
 
@@ -427,9 +427,9 @@ public class MainClass
     }
 
     private static PwmApplication loadPwmApplication(
-            final File applicationPath,
+            final Path applicationPath,
             final AppConfig config,
-            final File configurationFile,
+            final Path configurationFile,
             final boolean readonly
     )
             throws PwmUnrecoverableException
@@ -457,9 +457,9 @@ public class MainClass
         return pwmApplication;
     }
 
-    private static File locateConfigurationFile( final File applicationPath )
+    private static Path locateConfigurationFile( final Path applicationPath )
     {
-        return new File( applicationPath + File.separator + PwmConstants.DEFAULT_CONFIG_FILE_FILENAME );
+        return applicationPath.resolve( PwmConstants.DEFAULT_CONFIG_FILE_FILENAME );
     }
 
     private static void out( final CharSequence txt )
@@ -467,9 +467,9 @@ public class MainClass
         System.out.println( txt );
     }
 
-    private static File figureApplicationPath( final MainOptions mainOptions ) throws PwmUnrecoverableException
+    private static Path figureApplicationPath( final MainOptions mainOptions ) throws PwmUnrecoverableException
     {
-        final File applicationPath;
+        final Path applicationPath;
         if ( mainOptions != null && mainOptions.getApplicationPath() != null )
         {
             applicationPath = mainOptions.getApplicationPath();
@@ -479,7 +479,7 @@ public class MainClass
             final Optional<Path> appPathStr = EnvironmentProperty.readApplicationPath( null );
             if ( appPathStr.isPresent() )
             {
-                applicationPath = appPathStr.get().toFile();
+                applicationPath = appPathStr.get();
             }
             else
             {
@@ -491,7 +491,7 @@ public class MainClass
             }
         }
 
-        LOGGER.debug( () -> "using applicationPath " + applicationPath.getAbsolutePath() );
+        LOGGER.debug( () -> "using applicationPath " + applicationPath );
         return applicationPath;
     }
 }

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

@@ -22,28 +22,26 @@ package password.pwm.util.cli;
 
 import password.pwm.util.logging.PwmLogLevel;
 
-import java.io.File;
 import java.io.IOException;
-import java.io.Serializable;
 import java.io.Writer;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.List;
 
-public class MainOptions implements Serializable
+public class MainOptions
 {
     private static final String OPT_DEBUG_LEVEL = "-debugLevel";
     private static final String OPT_APP_PATH = "-applicationPath";
     private static final String OPT_FORCE = "-force";
 
-
     private PwmLogLevel pwmLogLevel;
-    private File applicationPath;
+    private Path applicationPath;
     private boolean forceFlag;
     private List<String> remainingArguments;
 
     MainOptions(
             final PwmLogLevel pwmLogLevel,
-            final File applicationPath,
+            final Path applicationPath,
             final boolean forceFlag,
             final List<String> remainingArguments
 
@@ -60,7 +58,7 @@ public class MainOptions implements Serializable
         return pwmLogLevel;
     }
 
-    public File getApplicationPath( )
+    public Path getApplicationPath( )
     {
         return applicationPath;
     }
@@ -81,7 +79,7 @@ public class MainOptions implements Serializable
     )
     {
         PwmLogLevel pwmLogLevel = null;
-        File applicationPath = null;
+        Path applicationPath = null;
         boolean forceFlag = false;
         final List<String> remainingArguments;
 
@@ -123,7 +121,7 @@ public class MainOptions implements Serializable
                         else
                         {
                             final String pathStr = arg.substring( OPT_APP_PATH.length() + 1 );
-                            applicationPath = new File( pathStr );
+                            applicationPath = Path.of( pathStr );
                         }
                     }
                     else if ( OPT_FORCE.equals( arg ) )

+ 8 - 6
server/src/main/java/password/pwm/util/cli/commands/ConfigDeleteCommand.java

@@ -22,8 +22,9 @@ package password.pwm.util.cli.commands;
 
 import password.pwm.util.cli.CliParameters;
 
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 
 public class ConfigDeleteCommand extends AbstractCliCommand
 {
@@ -31,8 +32,8 @@ public class ConfigDeleteCommand extends AbstractCliCommand
     public void doCommand( )
             throws IOException
     {
-        final File configurationFile = cliEnvironment.getConfigurationFile();
-        if ( configurationFile == null || !configurationFile.exists() )
+        final Path configurationFile = cliEnvironment.getConfigurationFile();
+        if ( configurationFile == null || !Files.exists( configurationFile ) )
         {
             out( "configuration file is not present" );
             return;
@@ -44,13 +45,14 @@ public class ConfigDeleteCommand extends AbstractCliCommand
             return;
         }
 
-        if ( configurationFile.delete() )
+        try
         {
+            Files.delete( configurationFile );
             out( "success: configuration file has been deleted" );
         }
-        else
+        catch ( final IOException e )
         {
-            out( "unable to delete file" );
+            out( "unable to delete file: " + e.getMessage() );
         }
     }
 

+ 5 - 4
server/src/main/java/password/pwm/util/cli/commands/ConfigNewCommand.java

@@ -25,9 +25,10 @@ import password.pwm.config.stored.StoredConfigurationFactory;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.cli.CliParameters;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Collections;
 
 public class ConfigNewCommand extends AbstractCliCommand
@@ -38,9 +39,9 @@ public class ConfigNewCommand extends AbstractCliCommand
     {
         final StoredConfiguration storedConfiguration = StoredConfigurationFactory.newConfig();
 
-        final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
+        final Path outputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
 
-        try ( FileOutputStream fileOutputStream = new FileOutputStream( outputFile, false ) )
+        try ( OutputStream fileOutputStream = Files.newOutputStream( outputFile ) )
         {
             StoredConfigurationFactory.output( storedConfiguration, fileOutputStream );
         }

+ 7 - 4
server/src/main/java/password/pwm/util/cli/commands/ConfigResetHttpsCommand.java

@@ -32,8 +32,9 @@ import password.pwm.error.PwmOperationalException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.cli.CliParameters;
 
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 
 public class ConfigResetHttpsCommand
         extends AbstractCliCommand
@@ -42,8 +43,8 @@ public class ConfigResetHttpsCommand
     public void doCommand( )
             throws IOException, PwmUnrecoverableException, PwmOperationalException
     {
-        final File configurationFile = cliEnvironment.getConfigurationFile();
-        if ( configurationFile == null || !configurationFile.exists() )
+        final Path configurationFile = cliEnvironment.getConfigurationFile();
+        if ( configurationFile == null || !Files.exists( configurationFile ) )
         {
             out( "configuration file is not present" );
             return;
@@ -54,7 +55,9 @@ public class ConfigResetHttpsCommand
             return;
         }
 
-        final ConfigurationFileManager configurationFileManager = new ConfigurationFileManager( cliEnvironment.getConfigurationFile(), SessionLabel.CLI_SESSION_LABEL );
+        final ConfigurationFileManager configurationFileManager = new ConfigurationFileManager(
+                cliEnvironment.getConfigurationFile(),
+                SessionLabel.CLI_SESSION_LABEL );
         final StoredConfiguration storedConfiguration = configurationFileManager.getStoredConfiguration();
 
         final StoredConfigurationModifier modifier = StoredConfigurationModifier.newModifier( storedConfiguration );

+ 9 - 6
server/src/main/java/password/pwm/util/cli/commands/ExportAuditCommand.java

@@ -29,9 +29,11 @@ import password.pwm.util.cli.CliParameters;
 import password.pwm.util.java.PwmTimeUtil;
 import password.pwm.util.java.TimeDuration;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
 import java.time.Instant;
 import java.util.Collections;
 
@@ -45,16 +47,17 @@ public class ExportAuditCommand extends AbstractCliCommand
         final AuditService auditManager = new AuditService();
         auditManager.init( pwmApplication, DomainID.systemId() );
 
-        final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
+        final Path outputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
 
         final Instant startTime = Instant.now();
-        out( "beginning output to " + outputFile.getAbsolutePath() );
+        out( "beginning output to " + outputFile );
         final int counter;
-        try ( FileOutputStream fileOutputStream = new FileOutputStream( outputFile, true ) )
+        try ( OutputStream fileOutputStream = Files.newOutputStream( outputFile, StandardOpenOption.APPEND ) )
         {
             counter = auditManager.outputVaultToCsv( fileOutputStream, PwmConstants.DEFAULT_LOCALE, false );
         }
-        out( "completed writing " + counter + " rows of audit output in " + PwmTimeUtil.asLongString( TimeDuration.fromCurrent( startTime ) ) );
+        out( "completed writing " + counter + " rows of audit output in "
+                + PwmTimeUtil.asLongString( TimeDuration.fromCurrent( startTime ) ) );
     }
 
     @Override

+ 12 - 8
server/src/main/java/password/pwm/util/cli/commands/ExportHttpsKeyStoreCommand.java

@@ -26,9 +26,10 @@ import password.pwm.util.cli.CliException;
 import password.pwm.util.cli.CliParameters;
 import password.pwm.util.secure.HttpsServerCertificateManager;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.KeyStore;
 import java.util.Arrays;
 
@@ -41,8 +42,8 @@ public class ExportHttpsKeyStoreCommand extends AbstractCliCommand
     void doCommand( )
             throws IOException, PwmUnrecoverableException, CliException
     {
-        final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
-        if ( outputFile.exists() )
+        final Path outputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
+        if ( Files.exists( outputFile ) )
         {
             out( "outputFile for ExportHttpsKeyStore cannot already exist" );
             return;
@@ -51,13 +52,16 @@ public class ExportHttpsKeyStoreCommand extends AbstractCliCommand
         final String password = getOptionalPassword();
         final String alias = ( String ) cliEnvironment.getOptions().get( ALIAS_OPTIONNAME );
 
-        final KeyStore keyStore = HttpsServerCertificateManager.keyStoreForApplication( cliEnvironment.getPwmApplication(), new PasswordData( password ), alias );
+        final KeyStore keyStore = HttpsServerCertificateManager.keyStoreForApplication(
+                cliEnvironment.getPwmApplication(),
+                new PasswordData( password ),
+                alias );
 
-        try ( FileOutputStream fos = new FileOutputStream( outputFile ) )
+        try ( OutputStream outputStream = Files.newOutputStream( outputFile ) )
         {
             try
             {
-                keyStore.store( fos, password.toCharArray() );
+                keyStore.store( outputStream, password.toCharArray() );
             }
             catch ( final Exception e )
             {
@@ -65,7 +69,7 @@ public class ExportHttpsKeyStoreCommand extends AbstractCliCommand
             }
         }
 
-        out( "successfully exported java keystore to " + outputFile.getAbsolutePath() );
+        out( "successfully exported java keystore to " + outputFile );
     }
 
     @Override

+ 10 - 7
server/src/main/java/password/pwm/util/cli/commands/ExportHttpsTomcatConfigCommand.java

@@ -27,11 +27,11 @@ import password.pwm.config.option.TLSVersion;
 import password.pwm.util.cli.CliParameters;
 import password.pwm.util.java.JavaHelper;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -39,15 +39,18 @@ import java.util.Set;
 
 public class ExportHttpsTomcatConfigCommand extends AbstractCliCommand
 {
+
+    public static final String PARAM_NAME_SOURCE_FILE = "sourceFile";
+
     @Override
     void doCommand( )
             throws IOException
     {
-        final File sourceFile = ( File ) cliEnvironment.getOptions().get( "sourceFile" );
-        final File outputFile = ( File ) cliEnvironment.getOptions().get( "outputFile" );
+        final Path sourceFile = ( Path ) cliEnvironment.getOptions().get( PARAM_NAME_SOURCE_FILE );
+        final Path outputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
         try (
-                InputStream fileInputStream = Files.newInputStream( sourceFile.toPath() );
-                OutputStream fileOutputStream = Files.newOutputStream( outputFile.toPath() )
+                InputStream fileInputStream = Files.newInputStream( sourceFile );
+                OutputStream fileOutputStream = Files.newOutputStream( outputFile )
         )
         {
             TomcatConfigWriter.writeOutputFile(
@@ -60,7 +63,7 @@ public class ExportHttpsTomcatConfigCommand extends AbstractCliCommand
         {
             out( "error during tomcat config file export: " + e.getMessage() );
         }
-        out( "successfully exported tomcat https settings to " + outputFile.getAbsolutePath() );
+        out( "successfully exported tomcat https settings to " + outputFile );
     }
 
     @Override
@@ -87,7 +90,7 @@ public class ExportHttpsTomcatConfigCommand extends AbstractCliCommand
             @Override
             public String getName( )
             {
-                return "sourceFile";
+                return PARAM_NAME_SOURCE_FILE;
             }
 
         };

+ 6 - 5
server/src/main/java/password/pwm/util/cli/commands/ExportLocalDBCommand.java

@@ -25,9 +25,10 @@ import password.pwm.util.cli.CliParameters;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBUtility;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Collections;
 
 public class ExportLocalDBCommand extends AbstractCliCommand
@@ -38,15 +39,15 @@ public class ExportLocalDBCommand extends AbstractCliCommand
     {
         final LocalDB localDB = cliEnvironment.getLocalDB();
 
-        final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
-        if ( outputFile.exists() )
+        final Path outputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
+        if ( Files.exists( outputFile ) )
         {
             out( "outputFile for exportLocalDB cannot already exist" );
             return;
         }
 
         final LocalDBUtility localDBUtility = new LocalDBUtility( localDB );
-        try ( FileOutputStream fileOutputStream = new FileOutputStream( outputFile ) )
+        try ( OutputStream fileOutputStream = Files.newOutputStream( outputFile ) )
         {
             localDBUtility.exportLocalDB( fileOutputStream, System.out );
         }

+ 5 - 5
server/src/main/java/password/pwm/util/cli/commands/ExportLogsCommand.java

@@ -27,11 +27,11 @@ import password.pwm.util.localdb.LocalDBException;
 import password.pwm.util.localdb.LocalDBStoredQueue;
 import password.pwm.util.logging.PwmLogEvent;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Collections;
 import java.util.Iterator;
 
@@ -52,10 +52,10 @@ public class ExportLogsCommand extends AbstractCliCommand
             return;
         }
 
-        final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
-        out( "outputting " + logQueue.size() + " log events to " + outputFile.getAbsolutePath() + "...." );
+        final Path outputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
+        out( "outputting " + logQueue.size() + " log events to " + outputFile + "...." );
 
-        try ( Writer outputWriter = new OutputStreamWriter( new FileOutputStream( outputFile ), PwmConstants.DEFAULT_CHARSET ) )
+        try ( Writer outputWriter = new OutputStreamWriter( Files.newOutputStream( outputFile ), PwmConstants.DEFAULT_CHARSET ) )
         {
             for ( final Iterator<String> iter = logQueue.descendingIterator(); iter.hasNext(); )
             {

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

@@ -39,10 +39,10 @@ import password.pwm.util.json.JsonFactory;
 import password.pwm.ws.server.rest.RestChallengesServer;
 
 import java.io.BufferedWriter;
-import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Writer;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Collections;
 import java.util.Map;
@@ -58,11 +58,11 @@ public class ExportResponsesCommand extends AbstractCliCommand
         final PwmApplication pwmApplication = cliEnvironment.getPwmApplication();
 
         final Instant startTime = Instant.now();
-        final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
+        final Path outputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
 
         long counter = 0;
 
-        try ( Writer writer = new BufferedWriter( new PrintWriter( outputFile, PwmConstants.DEFAULT_CHARSET.toString() ) ); )
+        try ( Writer writer = new BufferedWriter( new PrintWriter( outputFile.toFile(), PwmConstants.DEFAULT_CHARSET.toString() ) ); )
         {
             for ( final PwmDomain pwmDomain : pwmApplication.domains().values() )
             {

+ 7 - 5
server/src/main/java/password/pwm/util/cli/commands/ExportStatsCommand.java

@@ -29,9 +29,11 @@ import password.pwm.util.cli.CliParameters;
 import password.pwm.util.java.PwmTimeUtil;
 import password.pwm.util.java.TimeDuration;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
 import java.util.Collections;
 
 public class ExportStatsCommand extends AbstractCliCommand
@@ -44,11 +46,11 @@ public class ExportStatsCommand extends AbstractCliCommand
         final PwmApplication pwmApplication = cliEnvironment.getPwmApplication();
         final StatisticsService statsManger = pwmApplication.getStatisticsService();
 
-        final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
+        final Path outputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
         final long startTime = System.currentTimeMillis();
-        out( "beginning output to " + outputFile.getAbsolutePath() );
+        out( "beginning output to " + outputFile );
         final int counter;
-        try ( FileOutputStream fileOutputStream = new FileOutputStream( outputFile, true ) )
+        try ( OutputStream fileOutputStream = Files.newOutputStream( outputFile, StandardOpenOption.APPEND ) )
         {
             counter = StatisticsUtils.outputStatsToCsv(
                     SessionLabel.CLI_SESSION_LABEL,

+ 6 - 5
server/src/main/java/password/pwm/util/cli/commands/ExportWordlistCommand.java

@@ -25,9 +25,10 @@ import password.pwm.util.cli.CliParameters;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBUtility;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Collections;
 
 public class ExportWordlistCommand extends AbstractCliCommand
@@ -38,15 +39,15 @@ public class ExportWordlistCommand extends AbstractCliCommand
     {
         final LocalDB localDB = cliEnvironment.getLocalDB();
 
-        final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
-        if ( outputFile.exists() )
+        final Path outputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
+        if ( Files.exists( outputFile ) )
         {
             out( "outputFile for ExportWordlist cannot already exist" );
             return;
         }
 
         final LocalDBUtility localDBUtility = new LocalDBUtility( localDB );
-        try ( FileOutputStream fileOutputStream = new FileOutputStream( outputFile ) )
+        try ( OutputStream fileOutputStream = Files.newOutputStream( outputFile ) )
         {
             localDBUtility.exportWordlist( fileOutputStream, System.out );
         }

+ 9 - 6
server/src/main/java/password/pwm/util/cli/commands/ImportHttpsKeyStoreCommand.java

@@ -31,9 +31,10 @@ import password.pwm.util.cli.CliParameters;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.secure.HttpsServerCertificateManager;
 
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Arrays;
 
 public class ImportHttpsKeyStoreCommand extends AbstractCliCommand
@@ -45,8 +46,8 @@ public class ImportHttpsKeyStoreCommand extends AbstractCliCommand
     void doCommand( )
             throws IOException, PwmUnrecoverableException, PwmOperationalException
     {
-        final File inputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_EXISTING_INPUT_FILE.getName() );
-        if ( inputFile == null || !inputFile.exists() )
+        final Path inputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_EXISTING_INPUT_FILE.getName() );
+        if ( inputFile == null || !Files.exists( inputFile ) )
         {
             out( CliParameters.REQUIRED_EXISTING_INPUT_FILE.getName() + " does not exist" );
             return;
@@ -66,11 +67,13 @@ public class ImportHttpsKeyStoreCommand extends AbstractCliCommand
         final String keyStorePassword = getOptionalPassword();
         final String inputAliasName = ( String ) cliEnvironment.getOptions().get( ALIAS_OPTIONNAME );
 
-        final ConfigurationFileManager configurationFileManager = new ConfigurationFileManager( cliEnvironment.getConfigurationFile(), SessionLabel.CLI_SESSION_LABEL );
+        final ConfigurationFileManager configurationFileManager = new ConfigurationFileManager(
+                cliEnvironment.getConfigurationFile(),
+                SessionLabel.CLI_SESSION_LABEL );
         final StoredConfiguration storedConfiguration = configurationFileManager.getStoredConfiguration();
         final StoredConfigurationModifier modifier = StoredConfigurationModifier.newModifier( storedConfiguration );
 
-        try ( FileInputStream fileInputStream = new FileInputStream( inputFile ) )
+        try ( InputStream fileInputStream = Files.newInputStream( inputFile ) )
         {
             HttpsServerCertificateManager.importKey(
                     modifier,

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

@@ -25,8 +25,8 @@ import password.pwm.util.cli.CliParameters;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBUtility;
 
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Path;
 import java.util.Collections;
 
 public class ImportLocalDBCommand extends AbstractCliCommand
@@ -48,7 +48,7 @@ public class ImportLocalDBCommand extends AbstractCliCommand
         }
 
         final LocalDBUtility pwmDBUtility = new LocalDBUtility( localDB );
-        final File inputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_EXISTING_INPUT_FILE.getName() );
+        final Path inputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_EXISTING_INPUT_FILE.getName() );
         try
         {
             pwmDBUtility.importLocalDB( inputFile, System.out );

+ 9 - 9
server/src/main/java/password/pwm/util/cli/commands/ImportPropertyConfigCommand.java

@@ -25,11 +25,11 @@ import password.pwm.config.stored.StoredConfigurationFactory;
 import password.pwm.util.PropertyConfigurationImporter;
 import password.pwm.util.cli.CliParameters;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Collections;
 
 /**
@@ -41,25 +41,25 @@ public class ImportPropertyConfigCommand extends AbstractCliCommand
     void doCommand( )
             throws IOException
     {
-        final File configFile = cliEnvironment.getConfigurationFile();
+        final Path configFile = cliEnvironment.getConfigurationFile();
 
-        if ( configFile.exists() )
+        if ( Files.exists( configFile ) )
         {
             out( "this command can not be run with an existing configuration in place.  Exiting..." );
             return;
         }
 
-        final File inputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_EXISTING_INPUT_FILE.getName() );
+        final Path inputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_EXISTING_INPUT_FILE.getName() );
 
-        try ( FileInputStream fileInputStream = new FileInputStream( inputFile ) )
+        try ( InputStream fileInputStream = Files.newInputStream( inputFile ) )
         {
             final PropertyConfigurationImporter importer = new PropertyConfigurationImporter();
             final StoredConfiguration storedConfiguration = importer.readConfiguration( fileInputStream );
 
-            try ( OutputStream outputStream = new FileOutputStream( configFile ) )
+            try ( OutputStream outputStream = Files.newOutputStream( configFile ) )
             {
                 StoredConfigurationFactory.output( storedConfiguration,  outputStream );
-                out( "output configuration file " + configFile.getAbsolutePath() );
+                out( "output configuration file " + configFile );
             }
         }
         catch ( final Exception e )

+ 5 - 5
server/src/main/java/password/pwm/util/cli/commands/ImportResponsesCommand.java

@@ -40,9 +40,9 @@ import password.pwm.util.java.TimeDuration;
 import password.pwm.util.json.JsonFactory;
 import password.pwm.ws.server.rest.RestChallengesServer;
 
-import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Collections;
 import java.util.Iterator;
@@ -55,7 +55,7 @@ public class ImportResponsesCommand extends AbstractCliCommand
     {
         final PwmApplication pwmApplication = cliEnvironment.getPwmApplication();
 
-        final File inputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_EXISTING_INPUT_FILE.getName() );
+        final Path inputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_EXISTING_INPUT_FILE.getName() );
 
         try
         {
@@ -67,12 +67,12 @@ public class ImportResponsesCommand extends AbstractCliCommand
         }
     }
 
-    private void doImport( final PwmApplication pwmApplication,  final File inputFile )
+    private void doImport( final PwmApplication pwmApplication,  final Path inputFile )
             throws IOException, PwmUnrecoverableException, ChaiUnavailableException
     {
-        final Iterator<String> lineIterator = Files.lines( inputFile.toPath() ).iterator();
+        final Iterator<String> lineIterator = Files.lines( inputFile ).iterator();
 
-        out( "importing stored responses from " + inputFile.getAbsolutePath() + "...." );
+        out( "importing stored responses from " + inputFile + "...." );
 
         int counter = 0;
         final Instant startTime = Instant.now();

+ 9 - 6
server/src/main/java/password/pwm/util/cli/commands/ResponseStatsCommand.java

@@ -44,10 +44,12 @@ import password.pwm.util.java.TimeDuration;
 import password.pwm.util.json.JsonFactory;
 import password.pwm.util.json.JsonProvider;
 
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.Serializable;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -77,12 +79,13 @@ public class ResponseStatsCommand extends AbstractCliCommand
                 throw new CliException( "error generating response statistics: " + e.getMessage(), e );
             }
         }
-        final File outputFile = ( File ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
+        final Path outputFile = ( Path ) cliEnvironment.getOptions().get( CliParameters.REQUIRED_NEW_OUTPUT_FILE.getName() );
         final long startTime = System.currentTimeMillis();
-        out( "beginning output to " + outputFile.getAbsolutePath() );
-        try ( FileOutputStream fileOutputStream = new FileOutputStream( outputFile, true ) )
+        out( "beginning output to " + outputFile );
+        try ( OutputStream fileOutputStream = Files.newOutputStream( outputFile, StandardOpenOption.APPEND ) )
         {
-            fileOutputStream.write( JsonFactory.get().serialize( responseStats, JsonProvider.Flag.PrettyPrint ).getBytes( PwmConstants.DEFAULT_CHARSET ) );
+            final String jsonString = JsonFactory.get().serialize( responseStats, JsonProvider.Flag.PrettyPrint );
+            fileOutputStream.write( jsonString.getBytes( PwmConstants.DEFAULT_CHARSET ) );
         }
         out( "completed writing stats output in " + PwmTimeUtil.asLongString( TimeDuration.fromCurrent( startTime ) ) );
     }

+ 5 - 6
server/src/main/java/password/pwm/util/cli/commands/UserReportCommand.java

@@ -33,11 +33,10 @@ import password.pwm.svc.report.ReportProcessRequest;
 import password.pwm.svc.report.ReportService;
 import password.pwm.util.cli.CliParameters;
 
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
@@ -51,9 +50,9 @@ public class UserReportCommand extends AbstractCliCommand
     void doCommand( )
             throws IOException
     {
-        final File outputFile = ( File ) cliEnvironment.getOptions().get( OUTPUT_FILE_OPTIONNAME );
+        final Path outputFile = ( Path ) cliEnvironment.getOptions().get( OUTPUT_FILE_OPTIONNAME );
 
-        try ( OutputStream outputFileStream = new BufferedOutputStream( new FileOutputStream( outputFile ) ) )
+        try ( OutputStream outputFileStream = Files.newOutputStream( outputFile ) )
         {
 
             final PwmApplication pwmApplication = cliEnvironment.getPwmApplication();
@@ -85,7 +84,7 @@ public class UserReportCommand extends AbstractCliCommand
         }
         catch ( final IOException | PwmUnrecoverableException e )
         {
-            out( "unable to open file '" + outputFile.getAbsolutePath() + "' for writing" );
+            out( "unable to open file '" + outputFile + "' for writing" );
             System.exit( -1 );
         }
 

+ 16 - 16
server/src/main/java/password/pwm/util/debug/FileInfoDebugItemGenerator.java

@@ -27,11 +27,11 @@ import password.pwm.util.java.PwmUtil;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.logging.PwmLogger;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
 
@@ -50,17 +50,17 @@ class FileInfoDebugItemGenerator implements AppItemGenerator
             throws IOException
     {
         final PwmApplication pwmApplication = debugItemInput.getPwmApplication();
-        final File applicationPath = pwmApplication.getPwmEnvironment().getApplicationPath();
-        final List<File> interestedFiles = new ArrayList<>();
+        final Path applicationPath = pwmApplication.getPwmEnvironment().getApplicationPath();
+        final List<Path> interestedFiles = new ArrayList<>();
 
         if ( pwmApplication.getPwmEnvironment().getContextManager() != null )
         {
             try
             {
-                final Optional<File> webInfPath = pwmApplication.getPwmEnvironment().getContextManager().locateWebInfFilePath();
-                if ( webInfPath.isPresent() && webInfPath.get().exists() )
+                final Optional<Path> webInfPath = pwmApplication.getPwmEnvironment().getContextManager().locateWebInfFilePath();
+                if ( webInfPath.isPresent() && Files.exists( webInfPath.get() ) )
                 {
-                    final File servletRootPath = webInfPath.get().getParentFile();
+                    final Path servletRootPath = webInfPath.get().getParent();
 
                     if ( servletRootPath != null )
                     {
@@ -97,18 +97,18 @@ class FileInfoDebugItemGenerator implements AppItemGenerator
             csvPrinter.printComment( StringUtil.join( headerRow, "," ) );
         }
 
-        final Iterator<FileSystemUtility.FileSummaryInformation> iter = FileSystemUtility.readFileInformation( interestedFiles );
-        while ( iter.hasNext() )
+        final List<FileSystemUtility.FileSummaryInformation> fileSummaries = FileSystemUtility.readFileInformation( interestedFiles );
+        for ( final FileSystemUtility.FileSummaryInformation fileSummaryInformation : fileSummaries )
         {
-            final FileSystemUtility.FileSummaryInformation fileSummaryInformation = iter.next();
             try
             {
-                final List<String> dataRow = new ArrayList<>();
-                dataRow.add( fileSummaryInformation.getFilepath() );
-                dataRow.add( fileSummaryInformation.getFilename() );
-                dataRow.add( StringUtil.toIsoDate( fileSummaryInformation.getModified() ) );
-                dataRow.add( String.valueOf( fileSummaryInformation.getSize() ) );
-                dataRow.add( fileSummaryInformation.getSha512Hash() );
+                final List<String> dataRow = List.of(
+                        fileSummaryInformation.getFilepath(),
+                        fileSummaryInformation.getFilename(),
+                        StringUtil.toIsoDate( fileSummaryInformation.getModified() ),
+                        String.valueOf( fileSummaryInformation.getSize() ),
+                        fileSummaryInformation.getSha512Hash() );
+
                 csvPrinter.printRecord( dataRow );
             }
             catch ( final Exception e )

+ 24 - 10
server/src/main/java/password/pwm/util/debug/RootFileSystemDebugItemGenerator.java

@@ -26,13 +26,15 @@ import password.pwm.PwmConstants;
 import password.pwm.util.json.JsonFactory;
 import password.pwm.util.json.JsonProvider;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.Serializable;
-import java.util.Arrays;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystems;
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.stream.Collectors;
+import java.util.Iterator;
+import java.util.List;
 
 class RootFileSystemDebugItemGenerator implements AppItemGenerator
 {
@@ -54,24 +56,36 @@ class RootFileSystemDebugItemGenerator implements AppItemGenerator
     @Builder
     private static class RootFileSystemInfo implements Serializable
     {
-        private String rootPath;
+        private String name;
+        private String type;
         private long totalSpace;
         private long freeSpace;
         private long usableSpace;
 
         static Collection<RootFileSystemInfo> forAllRootFileSystems()
+                throws IOException
         {
-            return Arrays.stream( File.listRoots() )
-                    .map( RootFileSystemInfo::forRoot )
-                    .collect( Collectors.toList() );
+            final Iterator<FileStore> fileStoreIterator = FileSystems.getDefault().getFileStores().iterator();
+
+            final List<RootFileSystemInfo> returnList = new ArrayList<>();
+            while ( fileStoreIterator.hasNext() )
+            {
+                final FileStore fileStore = fileStoreIterator.next();
+                final RootFileSystemInfo rootFileSystemInfo = RootFileSystemInfo.forRoot( fileStore );
+                returnList.add( rootFileSystemInfo );
+            }
+
+            return List.copyOf( returnList );
         }
 
-        static RootFileSystemInfo forRoot( final File fileRoot )
+        static RootFileSystemInfo forRoot( final FileStore fileRoot )
+                throws IOException
         {
             return RootFileSystemInfo.builder()
-                    .rootPath( fileRoot.getAbsolutePath() )
+                    .name( fileRoot.name() )
+                    .type( fileRoot.type() )
                     .totalSpace( fileRoot.getTotalSpace() )
-                    .freeSpace( fileRoot.getFreeSpace() )
+                    .freeSpace( fileRoot.getUnallocatedSpace() )
                     .usableSpace( fileRoot.getUsableSpace() )
                     .build();
         }

+ 14 - 0
server/src/main/java/password/pwm/util/i18n/LocaleHelper.java

@@ -494,6 +494,20 @@ public class LocaleHelper
         return getLocalizedMessage( locale, Display.Value_NotApplicable, null );
     }
 
+    public static String orNotApplicable( final Object input, final Locale locale )
+    {
+        if ( input == null )
+        {
+            return valueNotApplicable( locale );
+        }
+        final String stringValue = input.toString();
+        if ( StringUtil.isEmpty( stringValue ) )
+        {
+            return valueNotApplicable( locale );
+        }
+        return stringValue;
+    }
+
     public static TextDirection textDirectionForLocale( final PwmDomain pwmDomain, final Locale locale )
     {
         final String rtlRegex = pwmDomain.getConfig().readAppProperty( AppProperty.L10N_RTL_REGEX );

+ 96 - 55
server/src/main/java/password/pwm/util/java/FileSystemUtility.java

@@ -21,40 +21,54 @@
 package password.pwm.util.java;
 
 import lombok.Value;
+import password.pwm.PwmConstants;
+import password.pwm.error.PwmException;
+import password.pwm.util.i18n.LocaleHelper;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.secure.PwmHashAlgorithm;
 import password.pwm.util.secure.SecureEngine;
 
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.Serializable;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
-import java.util.stream.Stream;
+import java.util.stream.Collectors;
 
 public class FileSystemUtility
 {
     private static final PwmLogger LOGGER = PwmLogger.forClass( FileSystemUtility.class );
 
-    public static Iterator<FileSummaryInformation> readFileInformation( final List<File> rootFiles )
+    public static List<FileSummaryInformation> readFileInformation( final List<Path> rootFiles )
     {
-        return rootFiles.stream().flatMap( FileSystemUtility::readFileInformation ).iterator();
+        final List<FileSummaryInformation> returnList = new ArrayList<>();
+        for ( final Path path : rootFiles )
+        {
+            returnList.addAll( readFileInformationHierarchy( path ) );
+        }
+        return List.copyOf( returnList );
     }
 
-    public static Stream<FileSummaryInformation> readFileInformation( final File rootFile )
+    public static List<FileSummaryInformation> readFileInformationHierarchy( final Path rootFile )
     {
         try
         {
-            return Files.walk( rootFile.toPath() )
-                    .map( Path::toFile )
-                    .filter( File::isFile )
-                    .map( FileSummaryInformation::fromFile );
+            final List<Path> paths =  Files.walk( rootFile )
+                    .filter( Files::isRegularFile )
+                    .collect( Collectors.toList() );
+
+            final List<FileSummaryInformation> returnList = new ArrayList<>();
+            for ( final Path path : paths )
+            {
+                returnList.add( FileSummaryInformation.fromFile( path ) );
+            }
+            return List.copyOf( returnList );
 
         }
         catch ( final IOException e )
@@ -62,76 +76,87 @@ public class FileSystemUtility
             LOGGER.trace( () -> "error during file summary load: " + e.getMessage() );
         }
 
-        return Stream.empty();
+        return Collections.emptyList();
     }
 
-    public static long getFileDirectorySize( final File dir )
+    public static long getFileDirectorySize( final Path dir )
     {
         try
         {
-            return Files.walk( dir.toPath() )
-                    .filter( path -> path.toFile().isFile() )
-                    .mapToLong( path -> path.toFile().length() )
-                    .sum();
+            final List<Path> files = Files.walk( dir )
+                    .filter( Files::isRegularFile )
+                    .collect( Collectors.toList() );
+
+            long totalSize = 0;
+            for ( final Path file : files )
+            {
+                totalSize += Files.size( file );
+            }
+            return totalSize;
         }
         catch ( final IOException e )
         {
-            LOGGER.error( () -> "error calculating disk size of '" + dir.getAbsolutePath() + "', error: " + e.getMessage(), e );
+            LOGGER.error( () -> "error calculating disk size of '" + dir + "', error: " + e.getMessage(), e );
         }
 
         return -1;
     }
 
-    public static File figureFilepath( final String filename, final File suggestedPath )
+    public static Path figureFilepath( final String filename, final Path suggestedPath )
     {
-        if ( filename == null || filename.length() < 1 )
-        {
-            return null;
-        }
+        Objects.requireNonNull( filename );
+        Objects.requireNonNull( suggestedPath );
 
-        if ( ( new File( filename ) ).isAbsolute() )
+        final Path filenamePath = Path.of( filename );
+
+        if ( filenamePath.isAbsolute() )
         {
-            return new File( filename );
+            return filenamePath;
         }
 
-        return new File( suggestedPath + File.separator + filename );
+        return suggestedPath.resolve( filename );
     }
 
-    public static long diskSpaceRemaining( final File file )
+    public static long diskSpaceRemaining( final Path file )
     {
-        return file.getFreeSpace();
+        try
+        {
+            return Files.getFileStore( file ).getUsableSpace();
+        }
+        catch ( final IOException e )
+        {
+            LOGGER.error( () -> "error calculating disk space remaining of '" + file + "', error: " + e.getMessage(), e );
+        }
+
+        return -1;
     }
 
-    public static void rotateBackups( final File inputFile, final int maxRotate )
+    public static void rotateBackups( final Path inputFile, final int maxRotate )
+            throws IOException
     {
-        if ( maxRotate < 1 )
+        if ( maxRotate < 1 || inputFile == null || !Files.exists( inputFile ) )
         {
             return;
         }
+
         for ( int i = maxRotate; i >= 0; i-- )
         {
-            final File thisFile = ( i == 0 ) ? inputFile : new File( inputFile.getAbsolutePath() + "-" + i );
-            final File youngerFile = ( i <= 1 ) ? inputFile : new File( inputFile.getAbsolutePath() + "-" + ( i - 1 ) );
+            final Path thisFile = ( i == 0 ) ? inputFile : addFilenameSuffix( inputFile, "-" + i );
+            final Path youngerFile = ( i <= 1 ) ? inputFile : addFilenameSuffix( inputFile, "-" + ( i - 1 ) );
 
             if ( i == maxRotate )
             {
-                if ( thisFile.exists() )
+                if ( Files.exists( thisFile ) )
                 {
-                    LOGGER.debug( () -> "deleting old backup file: " + thisFile.getAbsolutePath() );
-                    if ( !thisFile.delete() )
-                    {
-                        LOGGER.error( () -> "unable to delete old backup file: " + thisFile.getAbsolutePath() );
-                    }
+                    LOGGER.debug( () -> "deleting old backup file: " + thisFile );
+                    Files.delete( thisFile );
                 }
             }
-            else if ( i == 0 || youngerFile.exists() )
+            else if ( i == 0 || Files.exists( youngerFile ) )
             {
-                final File destFile = new File( inputFile.getAbsolutePath() + "-" + ( i + 1 ) );
-                LOGGER.debug( () -> "backup file " + thisFile.getAbsolutePath() + " renamed to " + destFile.getAbsolutePath() );
-                if ( !thisFile.renameTo( destFile ) )
-                {
-                    LOGGER.debug( () -> "unable to rename file " + thisFile.getAbsolutePath() + " to " + destFile.getAbsolutePath() );
-                }
+                final Path destFile = addFilenameSuffix( inputFile, "-" + ( i + 1 ) );
+                LOGGER.debug( () -> "renaming backup file " + thisFile + " to " + destFile );
+                Files.move( thisFile, destFile );
             }
         }
     }
@@ -145,23 +170,24 @@ public class FileSystemUtility
         private final long size;
         private final String sha512Hash;
 
-        public static FileSummaryInformation fromFile( final File file )
+        public static FileSummaryInformation fromFile( final Path file )
+                throws IOException
         {
             final String sha512Hash;
             try
             {
-                sha512Hash = SecureEngine.hash( new FileInputStream( file ), PwmHashAlgorithm.SHA512 );
+                sha512Hash = SecureEngine.hash( file, PwmHashAlgorithm.SHA512 );
             }
-            catch ( final IOException exception )
+            catch ( final PwmException exception )
             {
                 throw new IllegalStateException( exception );
             }
 
             return new FileSummaryInformation(
-                    file.getName(),
-                    file.getParentFile().getAbsolutePath(),
-                    Instant.ofEpochMilli( file.lastModified() ),
-                    file.length(),
+                    LocaleHelper.orNotApplicable( file.getFileName(), PwmConstants.DEFAULT_LOCALE ),
+                    LocaleHelper.orNotApplicable( file.getParent(), PwmConstants.DEFAULT_LOCALE ),
+                    Files.getLastModifiedTime( file ).toInstant(),
+                    Files.size( file ),
                     sha512Hash
             );
         }
@@ -184,11 +210,26 @@ public class FileSystemUtility
         }
     }
 
-    public static File createDirectory( final Path basePath, final String newDirectoryName )
+    public static Path createDirectory( final Path basePath, final String newDirectoryName )
             throws IOException
     {
-        final Path path = Path.of( basePath.toString() + File.separator + newDirectoryName );
-        final Path newPath = Files.createDirectories( path );
-        return newPath.toFile();
+        final Path path = basePath.resolve( newDirectoryName );
+        return Files.createDirectories( path );
+    }
+
+    public static Path addFilenameSuffix( final Path path, final String suffix )
+            throws IOException
+    {
+        final Path filenamePath = path.getFileName();
+        if ( filenamePath == null )
+        {
+            throw new IOException( "can not add suffix to empty filename" );
+        }
+        final String filename = filenamePath.toString();
+        if ( StringUtil.isEmpty( filename ) )
+        {
+            throw new IOException( "can not add suffix to empty filename" );
+        }
+        return path.resolveSibling( filename + suffix );
     }
 }

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

@@ -27,8 +27,8 @@ import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 
 import java.io.Closeable;
-import java.io.File;
 import java.io.Serializable;
+import java.nio.file.Path;
 import java.sql.Connection;
 import java.sql.Driver;
 import java.sql.PreparedStatement;
@@ -58,7 +58,7 @@ public abstract class AbstractJDBCLocalDB implements LocalDBProvider
     private static final String WIDTH_KEY = String.valueOf( LocalDB.MAX_KEY_LENGTH );
 
     protected Driver driver;
-    protected File dbDirectory;
+    protected Path dbDirectory;
 
     // cache of dbIterators
     private final Set<LocalDB.LocalDBIterator<Map.Entry<String, String>>> dbIterators = Collections.newSetFromMap(
@@ -280,7 +280,7 @@ public abstract class AbstractJDBCLocalDB implements LocalDBProvider
     }
 
     @Override
-    public void init( final File dbDirectory, final Map<String, String> initParams, final Map<Parameter, String> parameters )
+    public void init( final Path dbDirectory, final Map<String, String> initParams, final Map<Parameter, String> parameters )
             throws LocalDBException
     {
         this.dbDirectory = dbDirectory;
@@ -603,7 +603,7 @@ public abstract class AbstractJDBCLocalDB implements LocalDBProvider
     }
 
     abstract Connection openConnection(
-            File databaseDirectory,
+            Path databaseDirectory,
             String driverClasspath,
             Map<String, String> initParams
     ) throws LocalDBException;
@@ -688,7 +688,7 @@ public abstract class AbstractJDBCLocalDB implements LocalDBProvider
     }
 
     @Override
-    public File getFileLocation( )
+    public Path getFileLocation( )
     {
         return dbDirectory;
     }

+ 5 - 4
server/src/main/java/password/pwm/util/localdb/DerbyLocalDB.java

@@ -27,7 +27,7 @@ import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 
-import java.io.File;
+import java.nio.file.Path;
 import java.sql.CallableStatement;
 import java.sql.Connection;
 import java.sql.Driver;
@@ -115,12 +115,13 @@ public class DerbyLocalDB extends AbstractJDBCLocalDB
 
     @Override
     Connection openConnection(
-            final File databaseDirectory,
+            final Path databaseDirectory,
             final String driverClasspath,
             final Map<String, String> initOptions
-    ) throws LocalDBException
+    )
+            throws LocalDBException
     {
-        final String filePath = databaseDirectory.getAbsolutePath() + File.separator + "derby-db";
+        final String filePath = databaseDirectory.resolve( "derby-db" ).toString();
         final String baseConnectionURL = "jdbc:derby:" + filePath;
         final String connectionURL = baseConnectionURL + ";create=true";
 

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

@@ -23,10 +23,10 @@ package password.pwm.util.localdb;
 import password.pwm.util.java.ClosableIterator;
 import password.pwm.util.java.EnumUtil;
 
-import java.io.File;
 import java.io.Serializable;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.nio.file.Path;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
@@ -109,7 +109,7 @@ public interface LocalDB
     void truncate( DB db )
             throws LocalDBException;
 
-    File getFileLocation( );
+    Path getFileLocation( );
 
     Map<String, Serializable> debugInfo( );
 

+ 4 - 3
server/src/main/java/password/pwm/util/localdb/LocalDBAdaptor.java

@@ -25,8 +25,8 @@ import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.util.java.StatisticCounterBundle;
 
-import java.io.File;
 import java.io.Serializable;
+import java.nio.file.Path;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashMap;
@@ -52,7 +52,7 @@ public class LocalDBAdaptor implements LocalDB
     }
 
     @Override
-    public File getFileLocation( )
+    public Path getFileLocation( )
     {
         return innerDB.getFileLocation();
     }
@@ -88,7 +88,8 @@ public class LocalDBAdaptor implements LocalDB
     }
 
     @WriteOperation
-    public void init( final File dbDirectory, final Map<String, String> initParameters, final Map<LocalDBProvider.Parameter, String> parameters ) throws LocalDBException
+    public void init( final Path dbDirectory, final Map<String, String> initParameters, final Map<LocalDBProvider.Parameter, String> parameters )
+            throws LocalDBException
     {
         innerDB.init( dbDirectory, initParameters, parameters );
     }

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

@@ -30,7 +30,8 @@ import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 
-import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Arrays;
 import java.util.Collections;
@@ -49,7 +50,7 @@ public class LocalDBFactory
     private static final Lock CREATION_LOCK = new ReentrantLock();
 
     public static LocalDB getInstance(
-            final File dbDirectory,
+            final Path dbDirectory,
             final boolean readonly,
             final PwmEnvironment pwmEnvironment,
             final AppConfig appConfig
@@ -119,7 +120,7 @@ public class LocalDBFactory
         }
     }
 
-    private static void logInstanceCreation( final File dbDirectory, final boolean readonly, final Instant startTime, final LocalDB localDB )
+    private static void logInstanceCreation( final Path dbDirectory, final boolean readonly, final Instant startTime, final LocalDB localDB )
     {
         LOGGER.info( () ->
         {
@@ -171,7 +172,7 @@ public class LocalDBFactory
 
     private static void initInstance(
             final LocalDBProvider pwmDBProvider,
-            final File dbFileLocation,
+            final Path dbFileLocation,
             final Map<String, String> initParameters,
             final String theClass,
             final Map<LocalDBProvider.Parameter, String> parameters
@@ -180,11 +181,8 @@ public class LocalDBFactory
     {
         try
         {
-            if ( dbFileLocation.mkdir() )
-            {
-                LOGGER.trace( () -> "created directory at " + dbFileLocation.getAbsolutePath() );
-            }
-
+            Files.createDirectories( dbFileLocation );
+            LOGGER.trace( () -> "created directory at " + dbFileLocation );
 
             pwmDBProvider.init( dbFileLocation, initParameters, parameters );
         }

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

@@ -20,8 +20,8 @@
 
 package password.pwm.util.localdb;
 
-import java.io.File;
 import java.io.Serializable;
+import java.nio.file.Path;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
@@ -54,7 +54,7 @@ public interface LocalDBProvider
             throws LocalDBException;
 
     @LocalDB.WriteOperation
-    void init( File dbDirectory, Map<String, String> initParameters, Map<Parameter, String> parameters )
+    void init( Path dbDirectory, Map<String, String> initParameters, Map<Parameter, String> parameters )
             throws LocalDBException;
 
     LocalDB.LocalDBIterator<Map.Entry<String, String>> iterator( LocalDB.DB db )
@@ -88,7 +88,7 @@ public interface LocalDBProvider
     void truncate( LocalDB.DB db )
             throws LocalDBException;
 
-    File getFileLocation( );
+    Path getFileLocation( );
 
     LocalDB.Status getStatus( );
 

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

@@ -40,8 +40,6 @@ import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
 
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -49,6 +47,8 @@ import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.Reader;
 import java.math.RoundingMode;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Collections;
 import java.util.EnumMap;
@@ -228,7 +228,7 @@ public class LocalDBUtility
         }
     }
 
-    public void importLocalDB( final File inputFile, final PrintStream out )
+    public void importLocalDB( final Path inputFile, final PrintStream out )
             throws PwmOperationalException, IOException
     {
         if ( inputFile == null )
@@ -236,19 +236,19 @@ public class LocalDBUtility
             throw new PwmOperationalException( PwmError.ERROR_INTERNAL, "inputFile for importLocalDB cannot be null" );
         }
 
-        if ( !inputFile.exists() )
+        if ( !Files.exists( inputFile ) )
         {
             throw new PwmOperationalException( PwmError.ERROR_INTERNAL, "inputFile for importLocalDB does not exist" );
         }
 
-        final long totalBytes = inputFile.length();
+        final long totalBytes = Files.size( inputFile );
 
         if ( totalBytes <= 0 )
         {
             throw new PwmOperationalException( PwmError.ERROR_INTERNAL, "inputFile for importLocalDB is empty" );
         }
 
-        try ( InputStream inputStream = new FileInputStream( inputFile ) )
+        try ( InputStream inputStream = Files.newInputStream( inputFile ) )
         {
             importLocalDB( inputStream, out, totalBytes );
         }

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

@@ -22,8 +22,8 @@ package password.pwm.util.localdb;
 
 import password.pwm.util.java.CollectionUtil;
 
-import java.io.File;
 import java.io.Serializable;
+import java.nio.file.Path;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
@@ -93,7 +93,7 @@ public class MemoryLocalDB implements LocalDBProvider
     @Override
     @LocalDB.WriteOperation
     public void init(
-            final File dbDirectory,
+            final Path dbDirectory,
             final Map<String, String> initParameters,
             final Map<LocalDBProvider.Parameter, String> parameters
     )
@@ -248,7 +248,7 @@ public class MemoryLocalDB implements LocalDBProvider
     }
 
     @Override
-    public File getFileLocation( )
+    public Path getFileLocation( )
     {
         return null;
     }

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

@@ -44,10 +44,10 @@ import password.pwm.util.json.JsonFactory;
 import password.pwm.util.logging.PwmLogger;
 
 import java.io.ByteArrayOutputStream;
-import java.io.File;
 import java.io.IOException;
 import java.io.Serializable;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 import java.time.Instant;
 import java.util.AbstractMap;
@@ -75,7 +75,7 @@ public class XodusLocalDB implements LocalDBProvider
     private static final int DEFAULT_MEMORY_USAGE = 50 * 1024 * 1024;
 
     private Environment environment;
-    private File fileLocation;
+    private Path fileLocation;
     private boolean readOnly;
 
     private enum Property
@@ -111,7 +111,7 @@ public class XodusLocalDB implements LocalDBProvider
 
     @Override
     public void init(
-            final File dbDirectory,
+            final Path dbDirectory,
             final Map<String, String> initParameters,
             final Map<Parameter, String> parameters
     )
@@ -124,7 +124,7 @@ public class XodusLocalDB implements LocalDBProvider
 
         final EnvironmentConfig environmentConfig = makeEnvironmentConfig( initParameters );
 
-        if ( Files.exists( getDirtyFile().toPath() ) )
+        if ( Files.exists( getDirtyFile() ) )
         {
             environmentConfig.setGcUtilizationFromScratch( true );
             LOGGER.warn( () -> "environment not closed cleanly, will re-calculate GC" );
@@ -136,9 +136,9 @@ public class XodusLocalDB implements LocalDBProvider
 
         try
         {
-            if ( !getDirtyFile().exists() )
+            if ( !Files.exists( getDirtyFile() ) )
             {
-                Files.createFile( getDirtyFile().toPath() );
+                Files.createFile( getDirtyFile() );
                 LOGGER.trace( () -> "created openLock file" );
             }
         }
@@ -162,7 +162,7 @@ public class XodusLocalDB implements LocalDBProvider
         readOnly = parameters.containsKey( Parameter.readOnly ) && Boolean.parseBoolean( parameters.get( Parameter.readOnly ) );
 
         LOGGER.trace( () -> "preparing to open with configuration " + JsonFactory.get().serializeMap( environmentConfig.getSettings(), String.class, Object.class ) );
-        environment = Environments.newInstance( dbDirectory.getAbsolutePath() + File.separator + FILE_SUB_PATH, environmentConfig );
+        environment = Environments.newInstance( dbDirectory.resolve( FILE_SUB_PATH ).toFile(), environmentConfig );
 
         LOGGER.trace( () -> "environment open (" + TimeDuration.fromCurrent( startTime ).asCompactString() + ")" );
 
@@ -183,7 +183,7 @@ public class XodusLocalDB implements LocalDBProvider
             LOGGER.trace( () -> "opened " + db + " with " + finalSize + " records" );
         }
 
-        outputReadme( new File( dbDirectory.getPath() + File.separator + FILE_SUB_PATH + File.separator + README_FILENAME ) );
+        outputReadme( dbDirectory.resolve( FILE_SUB_PATH ).resolve( README_FILENAME ) );
     }
 
     @Override
@@ -197,7 +197,7 @@ public class XodusLocalDB implements LocalDBProvider
 
         try
         {
-            Files.deleteIfExists( getDirtyFile().toPath() );
+            Files.deleteIfExists( getDirtyFile() );
             LOGGER.trace( () -> "deleted openLock file" );
         }
         catch ( final IOException e )
@@ -474,7 +474,7 @@ public class XodusLocalDB implements LocalDBProvider
     }
 
     @Override
-    public File getFileLocation( )
+    public Path getFileLocation( )
     {
         return fileLocation;
     }
@@ -653,14 +653,14 @@ public class XodusLocalDB implements LocalDBProvider
         return Collections.emptySet();
     }
 
-    private static void outputReadme( final File xodusPath )
+    private static void outputReadme( final Path xodusPath )
     {
         try
         {
             final ResourceBundle resourceBundle = ResourceBundle.getBundle( XodusLocalDB.class.getName() );
             final String contents = resourceBundle.getString( "ReadmeContents" );
             final byte[] byteContents = contents.getBytes( PwmConstants.DEFAULT_CHARSET );
-            Files.write( xodusPath.toPath(), byteContents, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING );
+            Files.write( xodusPath, byteContents, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING );
         }
         catch ( final IOException e )
         {
@@ -668,8 +668,8 @@ public class XodusLocalDB implements LocalDBProvider
         }
     }
 
-    private File getDirtyFile()
+    private Path getDirtyFile()
     {
-        return new File( this.getFileLocation().getAbsolutePath() + File.separator + FILE_SUB_PATH + File.separator + "xodus.open" );
+        return this.getFileLocation().resolve( FILE_SUB_PATH ).resolve( "xodus.open" );
     }
 }

+ 15 - 26
server/src/main/java/password/pwm/util/logging/PwmLogManager.java

@@ -48,10 +48,10 @@ import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.localdb.LocalDB;
 import password.pwm.util.localdb.LocalDBException;
 
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Callable;
 
@@ -103,18 +103,18 @@ public class PwmLogManager
     public static void initializeLogging(
             final PwmApplication pwmApplication,
             final AppConfig config,
-            final File pwmApplicationPath,
+            final Path pwmApplicationPath,
             final PwmLogSettings pwmLogSettings
     )
     {
         if ( pwmApplicationPath != null )
         {
-            final File logbackXmlInAppPath = new File( pwmApplicationPath.getPath() + File.separator + "logback.xml" );
-            if ( logbackXmlInAppPath.exists() )
+            final Path logbackXmlInAppPath = pwmApplicationPath.resolve( "logback.xml" );
+            if ( Files.exists( logbackXmlInAppPath ) )
             {
                 if ( PwmLogUtil.initLogbackFromXmlFile( logbackXmlInAppPath ) )
                 {
-                    LOGGER.info( () -> "used appPath logback xml file '" + logbackXmlInAppPath.getPath()
+                    LOGGER.info( () -> "used appPath logback xml file '" + logbackXmlInAppPath
                             + "' to configure logging system, will ignore configured logging settings " );
                 }
             }
@@ -185,13 +185,8 @@ public class PwmLogManager
         final LoggerContext context = getLoggerContext();
         final ConfigurationWatchList configurationWatchList = ConfigurationWatchListUtil.getConfigurationWatchList( context );
 
-        if ( configurationWatchList != null )
-        {
-            final List<File> watchList = ConfigurationWatchListUtil.getConfigurationWatchList( context ).getCopyOfFileWatchList();
-            return !watchList.isEmpty();
-        }
-
-        return false;
+        return configurationWatchList != null
+                && ConfigurationWatchListUtil.getConfigurationWatchList( context ).getCopyOfFileWatchList().isEmpty();
     }
 
     static LoggerContext getLoggerContext()
@@ -259,31 +254,25 @@ public class PwmLogManager
     private static void initFileLogger(
             final AppConfig config,
             final PwmLogLevel fileLogLevel,
-            final File pwmApplicationPath
+            final Path pwmApplicationPath
     )
     {
         // configure file logging
         final String logDirectorySetting = config.readAppProperty( AppProperty.LOGGING_FILE_PATH );
-        final File logDirectory = FileSystemUtility.figureFilepath( logDirectorySetting, pwmApplicationPath );
+        final Path logDirectory = FileSystemUtility.figureFilepath( logDirectorySetting, pwmApplicationPath );
 
         if ( logDirectory != null && fileLogLevel != null )
         {
             try
             {
-                if ( !logDirectory.exists() )
+                if ( !Files.exists( logDirectory ) )
                 {
-                    if ( logDirectory.mkdir() )
-                    {
-                        LOGGER.info( () -> "created directory " + logDirectory.getAbsoluteFile() );
-                    }
-                    else
-                    {
-                        throw new IOException( "failed to create directory " + logDirectory.getAbsoluteFile() );
-                    }
+                    Files.createDirectories( logDirectory );
+                    LOGGER.info( () -> "created directory " + logDirectory );
                 }
 
-                final String fileName = logDirectory.getAbsolutePath() + File.separator + PwmConstants.PWM_APP_NAME + ".log";
-                final String fileNamePattern = logDirectory.getAbsolutePath() + File.separator + PwmConstants.PWM_APP_NAME + ".log.%d{yyyy-MM-dd}.%i.gz";
+                final String fileName = logDirectory.resolve( PwmConstants.PWM_APP_NAME + ".log" ).toString();
+                final String fileNamePattern = logDirectory.resolve( PwmConstants.PWM_APP_NAME + ".log.%d{yyyy-MM-dd}.%i.gz" ).toString();
 
                 final LoggerContext logCtx = getLoggerContext();
 

+ 14 - 4
server/src/main/java/password/pwm/util/logging/PwmLogUtil.java

@@ -44,8 +44,11 @@ import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.json.JsonFactory;
 
-import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 import java.io.Serializable;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.List;
 import java.util.function.Function;
 import java.util.function.Supplier;
@@ -108,9 +111,9 @@ class PwmLogUtil
      * @return true if successfully loaded and initialized loggers
      * @see <a href=" https://logback.qos.ch/manual/configuration.html#joranDirectly">Logback Docs</a>
      */
-    public static boolean initLogbackFromXmlFile( final File file )
+    public static boolean initLogbackFromXmlFile( final Path file )
     {
-        if ( !file.exists() )
+        if ( !Files.exists( file ) )
         {
             return false;
         }
@@ -124,10 +127,17 @@ class PwmLogUtil
             configurator.setContext( context );
 
             context.reset();
-            configurator.doConfigure( file );
+            try ( InputStream inputStream = Files.newInputStream( file ) )
+            {
+                configurator.doConfigure( inputStream );
+            }
 
             return true;
         }
+        catch ( final IOException e  )
+        {
+            /* can't be logged... */
+        }
         catch ( final JoranException je )
         {
             context.reset();

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

@@ -37,16 +37,13 @@ import javax.crypto.SecretKey;
 import javax.crypto.spec.GCMParameterSpec;
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Writer;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.GeneralSecurityException;
 import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.time.Instant;
 import java.util.Arrays;
 import java.util.Objects;
@@ -276,33 +273,16 @@ public class SecureEngine
     }
 
     public static String hash(
-            final File file,
+            final Path file,
             final PwmHashAlgorithm hashAlgorithm
     )
             throws PwmUnrecoverableException
     {
-        try
+        try ( InputStream inputStream = Files.newInputStream( file ) )
         {
-            final MessageDigest messageDigest = MessageDigest.getInstance( hashAlgorithm.getAlgName() );
-            final int bufferSize = (int) Math.min( file.length(), HASH_FILE_BUFFER_SIZE );
-            final FileChannel fileChannel = FileChannel.open( file.toPath() );
-            final ByteBuffer byteBuffer = ByteBuffer.allocateDirect( bufferSize );
-
-            while ( fileChannel.read( byteBuffer ) > 0 )
-            {
-                // redundant cast to buffer to solve jdk8/9 inter-op issue
-                ( ( Buffer ) byteBuffer ).flip();
-
-                messageDigest.update( byteBuffer );
-
-                // redundant cast to buffer to solve jdk8/9 inter-op issue
-                ( ( Buffer ) byteBuffer ).clear();
-            }
-
-            return JavaHelper.binaryArrayToHex( messageDigest.digest() );
-
+            return hash( inputStream, hashAlgorithm );
         }
-        catch ( final NoSuchAlgorithmException | IOException e )
+        catch ( final IOException e )
         {
             final String errorMsg = "unexpected error during file hash operation: " + e.getMessage();
             final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_CRYPT_ERROR, errorMsg );

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

@@ -48,11 +48,11 @@ import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.URI;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.GeneralSecurityException;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
@@ -356,7 +356,7 @@ public class X509Utils
 
     public static void outputKeystore(
             final KeyStore keyStore,
-            final File keyStoreFile,
+            final Path keyStoreFile,
             final String password
     )
             throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException
@@ -364,12 +364,9 @@ public class X509Utils
         final ByteArrayOutputStream outputContents = new ByteArrayOutputStream();
         keyStore.store( outputContents, password.toCharArray() );
 
-        if ( keyStoreFile.exists() )
-        {
-            Files.delete( keyStoreFile.toPath() );
-        }
+        Files.deleteIfExists( keyStoreFile );
 
-        try ( OutputStream fileOutputStream = Files.newOutputStream( keyStoreFile.toPath() ) )
+        try ( OutputStream fileOutputStream = Files.newOutputStream( keyStoreFile ) )
         {
             fileOutputStream.write( outputContents.toByteArray() );
         }

+ 1 - 1
server/src/test/java/password/pwm/EnvironmentPropertyTest.java

@@ -48,7 +48,7 @@ class EnvironmentPropertyTest
             throws Exception
     {
         {
-            final Path propFilePath = Path.of( temporaryPath.toString(), PwmConstants.DEFAULT_ENVIRONMENT_PROPERTIES_FILENAME );
+            final Path propFilePath = temporaryPath.resolve( PwmConstants.DEFAULT_ENVIRONMENT_PROPERTIES_FILENAME );
             final Properties outputProps = new Properties();
             outputProps.setProperty( EnvironmentProperty.InstanceID.name(), "TEST-VALUE-22" );
             try ( OutputStream outputStream = Files.newOutputStream( propFilePath ) )

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

@@ -35,7 +35,6 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.localdb.TestHelper;
 
-import java.io.File;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.ArrayList;
@@ -55,7 +54,7 @@ public class DomainConfigTest
         final StoredConfigKey key = StoredConfigKey.forSetting( PwmSetting.LDAP_PROFILE_LIST, null, DomainID.DOMAIN_ID_DEFAULT );
         modifier.writeSetting( key, StringArrayValue.create( List.of( "ldap1", "ldap2", "ldap3", "ldap4", "ldap5" ) ), null );
 
-        final File localDbTestFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-testLdapProfileOrdering" );
+        final Path localDbTestFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-testLdapProfileOrdering" );
         final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( localDbTestFolder, AppConfig.forStoredConfig( modifier.newStoredConfiguration() ) );
         final AppConfig appConfig = pwmApplication.getConfig();
         final DomainConfig domainConfig = appConfig.getDomainConfigs().get( DomainID.DOMAIN_ID_DEFAULT );

+ 1 - 2
server/src/test/java/password/pwm/config/profile/PasswordRuleReaderHelperTest.java

@@ -30,7 +30,6 @@ import password.pwm.util.localdb.TestHelper;
 import password.pwm.util.macro.MacroRequest;
 import password.pwm.util.password.PasswordRuleReaderHelper;
 
-import java.io.File;
 import java.nio.file.Path;
 import java.util.HashMap;
 import java.util.List;
@@ -54,7 +53,7 @@ public class PasswordRuleReaderHelperTest
                     "sn", "Flintstone" );
         }
 
-        final File testFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-makeMacroRequest" );
+        final Path testFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-makeMacroRequest" );
         final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( testFolder );
 
         final UserInfoBean userInfo = UserInfoBean.builder()

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

@@ -29,7 +29,6 @@ import password.pwm.config.AppConfig;
 import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.localdb.TestHelper;
 
-import java.io.File;
 import java.io.InputStream;
 import java.nio.file.Path;
 
@@ -54,7 +53,7 @@ public class StoredConfigurationTest
     public void configurationHashTest()
             throws Exception
     {
-        final File testFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-configurationHashTest" );
+        final Path testFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-configurationHashTest" );
         final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( testFolder, appConfig );
         final String configHash = StoredConfigurationUtil.valueHash( appConfig.getStoredConfiguration() );
 

+ 9 - 10
server/src/test/java/password/pwm/http/client/PwmHttpClientTest.java

@@ -55,7 +55,7 @@ import password.pwm.util.secure.X509Utils;
 import password.pwm.util.secure.self.SelfCertFactory;
 import password.pwm.util.secure.self.SelfCertSettings;
 
-import java.io.File;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.security.KeyStore;
 import java.security.cert.X509Certificate;
@@ -79,10 +79,9 @@ public class PwmHttpClientTest
     void initWireMockImpl()
             throws Exception
     {
-        final File httpsKeystoreFile = File.createTempFile(
+        final Path httpsKeystoreFile = Files.createTempFile( temporaryFolder,
                 "pwm-" + PwmHttpClientTest.class.getName() + "-",
-                ".jks",
-                temporaryFolder.toFile() );
+                ".jks" );
 
         final KeyStore keyStore = SelfCertFactory.generateNewCert(
                 SelfCertSettings.builder().subjectAlternateName( CERT_HOSTNAME ).build(),
@@ -96,7 +95,7 @@ public class PwmHttpClientTest
 
         final WireMockConfiguration wireMockConfiguration = WireMockConfiguration.wireMockConfig()
                 .keystorePassword( CERT_PASSWORD )
-                .keystorePath( httpsKeystoreFile.getAbsolutePath() )
+                .keystorePath( httpsKeystoreFile.toString() )
                 .dynamicPort()
                 .dynamicHttpsPort();
 
@@ -126,7 +125,7 @@ public class PwmHttpClientTest
         final String url = String.format( "http://localhost:%d/simpleHello", wireMockRule.port() );
 
         // Obtain the HTTP client
-        final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( temporaryFolder.toFile(), makeAppConfig( url, false, false ) );
+        final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( temporaryFolder, makeAppConfig( url, false, false ) );
         final PwmHttpClient httpClient = pwmDomain.getHttpClientService().getPwmHttpClient( SessionLabel.TEST_SESSION_LABEL );
 
         // Execute the HTTP request
@@ -160,7 +159,7 @@ public class PwmHttpClientTest
         final String url = String.format( "https://localhost:%d/simpleHello", wireMockRule.httpsPort() );
 
         // Obtain the HTTP client
-        final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( temporaryFolder.toFile(), makeAppConfig( null, false, false ) );
+        final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( temporaryFolder, makeAppConfig( null, false, false ) );
         final PwmHttpClient httpClient = pwmDomain.getHttpClientService().getPwmHttpClient( SessionLabel.TEST_SESSION_LABEL );
 
         // Execute the HTTP request
@@ -189,7 +188,7 @@ public class PwmHttpClientTest
         final String url = String.format( "https://localhost:%d/simpleHello", wireMockRule.httpsPort() );
 
         // Obtain the HTTP client
-        final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( temporaryFolder.toFile(), makeAppConfig( null, true, false ) );
+        final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( temporaryFolder, makeAppConfig( null, true, false ) );
         final PwmHttpClient httpClient = pwmApplication.getHttpClientService().getPwmHttpClient(
                 PwmHttpClientConfiguration.builder().trustManagerType( PwmHttpClientConfiguration.TrustManagerType.promiscuous ).build(), SessionLabel.TEST_SESSION_LABEL
         );
@@ -221,7 +220,7 @@ public class PwmHttpClientTest
 
 
         // Obtain the HTTP client
-        final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( temporaryFolder.toFile(), makeAppConfig( null, false, true ) );
+        final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( temporaryFolder, makeAppConfig( null, false, true ) );
         final PwmHttpClient httpClient = pwmDomain.getHttpClientService().getPwmHttpClient(
                 PwmHttpClientConfiguration.builder().trustManagerType( PwmHttpClientConfiguration.TrustManagerType.configuredCertificates )
                         .certificates( httpsCertificates ).build(), SessionLabel.TEST_SESSION_LABEL
@@ -255,7 +254,7 @@ public class PwmHttpClientTest
         final String proxyUrl = String.format( "http://localhost:%d/simpleHello", wireMockRule.port() );
 
         // Obtain the HTTP client
-        final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( temporaryFolder.toFile(), makeAppConfig( proxyUrl, false, false ) );
+        final PwmApplication pwmDomain = TestHelper.makeTestPwmApplication( temporaryFolder, makeAppConfig( proxyUrl, false, false ) );
         final PwmHttpClient httpClient = pwmDomain.getHttpClientService().getPwmHttpClient(
                 PwmHttpClientConfiguration.builder().trustManagerType( PwmHttpClientConfiguration.TrustManagerType.configuredCertificates )
                         .certificates( httpsCertificates ).build(), SessionLabel.TEST_SESSION_LABEL

+ 1 - 1
server/src/test/java/password/pwm/svc/event/CEFAuditFormatterTest.java

@@ -64,7 +64,7 @@ public class CEFAuditFormatterTest
                 + " perpetratorID=per\\|son perpetratorDN=cn\\=per\\|son,o\\=org sourceAddress=2001:DB8:D:B8:35cc::/64 sourceHost=ws31222";
 
         final CEFAuditFormatter cefAuditFormatter = new CEFAuditFormatter();
-        final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( temporaryFolder.toFile() );
+        final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( temporaryFolder );
         final String output = cefAuditFormatter.convertAuditRecordToMessage( pwmApplication, auditRecord );
         Assertions.assertEquals( expectedOutput, output );
     }

+ 1 - 1
server/src/test/java/password/pwm/svc/event/JsonAuditFormatterTest.java

@@ -57,7 +57,7 @@ public class JsonAuditFormatterTest
         final String expectedOutput = PwmConstants.PWM_APP_NAME + " " + JsonFactory.get().serialize( auditRecord );
         final AuditFormatter auditFormatter = new JsonAuditFormatter();
 
-        final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( temporaryFolder.toFile() );
+        final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( temporaryFolder );
 
         final String output = auditFormatter.convertAuditRecordToMessage( pwmApplication, auditRecord );
         Assertions.assertEquals( expectedOutput, output );

+ 1 - 1
server/src/test/java/password/pwm/svc/event/LdapXmlUserHistoryTest.java

@@ -51,7 +51,7 @@ public class LdapXmlUserHistoryTest
     public void inputParserTest()
             throws Exception
     {
-        final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( temporaryFolder.toFile() );
+        final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( temporaryFolder );
         final PwmDomain pwmDomain = pwmApplication.domains().get( DomainID.DOMAIN_ID_DEFAULT );
         final ResourceBundle bundle = ResourceBundle.getBundle( LdapXmlUserHistoryTest.class.getName() );
         final String xmlValue1 =  bundle.getString( "xmlValue1" );

+ 1 - 2
server/src/test/java/password/pwm/svc/wordlist/WordlistServiceTest.java

@@ -32,7 +32,6 @@ import password.pwm.config.stored.StoredConfigurationFactory;
 import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.localdb.TestHelper;
 
-import java.io.File;
 import java.net.URL;
 import java.nio.file.Path;
 
@@ -159,7 +158,7 @@ public class WordlistServiceTest
         final URL url = this.getClass().getResource( "test-wordlist.zip" );
         Mockito.when( appConfig.readAppProperty( AppProperty.WORDLIST_BUILTIN_PATH ) ).thenReturn( url.toString() );
 
-        final File testFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-makeWordlistService" );
+        final Path testFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-makeWordlistService" );
         final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( testFolder, appConfig );
         return pwmApplication.getWordlistService();
     }

+ 1 - 2
server/src/test/java/password/pwm/util/localdb/LocalDBBasicTest.java

@@ -30,7 +30,6 @@ import password.pwm.PwmApplication;
 import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.secure.PwmRandom;
 
-import java.io.File;
 import java.nio.file.Path;
 import java.util.HashSet;
 import java.util.List;
@@ -52,7 +51,7 @@ public class LocalDBBasicTest
     @BeforeEach
     public void setUp() throws Exception
     {
-        final File localDbTestFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-stored-queue-test" );
+        final Path localDbTestFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-stored-queue-test" );
         final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( localDbTestFolder );
         localDB = LocalDBFactory.getInstance( localDbTestFolder, false, pwmApplication.getPwmEnvironment(), pwmApplication.getConfig() );
     }

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

@@ -31,8 +31,8 @@ import password.pwm.config.AppConfig;
 import password.pwm.config.PwmSetting;
 import password.pwm.config.stored.StoredConfigurationFactory;
 import password.pwm.util.EventRateMeter;
-import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.Percent;
+import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.java.StringUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.json.JsonFactory;
@@ -42,7 +42,6 @@ import password.pwm.util.logging.PwmLogLevel;
 import password.pwm.util.logging.PwmLogMessage;
 import password.pwm.util.secure.PwmRandom;
 
-import java.io.File;
 import java.io.Serializable;
 import java.math.RoundingMode;
 import java.nio.file.Path;
@@ -85,7 +84,7 @@ public class LocalDBLoggerExtendedTest
     @BeforeEach
     public void setUp() throws Exception
     {
-        final File localDBPath = FileSystemUtility.createDirectory( temporaryFolder, "test-localdb-logger-test" );
+        final Path localDBPath = FileSystemUtility.createDirectory( temporaryFolder, "test-localdb-logger-test" );
 
         config = AppConfig.forStoredConfig( StoredConfigurationFactory.newConfig() );
 

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

@@ -28,7 +28,6 @@ import org.junit.jupiter.api.io.TempDir;
 import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.java.TimeDuration;
 
-import java.io.File;
 import java.nio.file.Path;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
@@ -48,7 +47,7 @@ public class LocalDBStoredQueueExtendedTest
     @BeforeAll
     public static void setUp() throws Exception
     {
-        final File fileLocation = FileSystemUtility.createDirectory( temporaryFolder, "localdb-storedqueue-test" );
+        final Path fileLocation = FileSystemUtility.createDirectory( temporaryFolder, "localdb-storedqueue-test" );
         localDB = LocalDBFactory.getInstance( fileLocation, false, null, null );
         storedQueue = LocalDBStoredQueue.createLocalDBStoredQueue( localDB, LocalDB.DB.TEMP, ENABLE_DEBUG_OUTPUT );
     }

+ 1 - 2
server/src/test/java/password/pwm/util/localdb/LocalDBStoredQueueTest.java

@@ -28,7 +28,6 @@ import org.junit.jupiter.api.io.TempDir;
 import password.pwm.PwmApplication;
 import password.pwm.util.java.FileSystemUtility;
 
-import java.io.File;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -48,7 +47,7 @@ public class LocalDBStoredQueueTest
     @BeforeEach
     public void setUp() throws Exception
     {
-        final File localDbTestFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-stored-queue-test" );
+        final Path localDbTestFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-stored-queue-test" );
         final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( localDbTestFolder );
         localDB = LocalDBFactory.getInstance( localDbTestFolder, false, pwmApplication.getPwmEnvironment(), pwmApplication.getConfig() );
         localDBStoredQueue = LocalDBStoredQueue.createLocalDBStoredQueue( localDB, LocalDB.DB.TEMP, true );

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

@@ -34,11 +34,11 @@ import password.pwm.config.value.StringValue;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.logging.PwmLogLevel;
 
-import java.io.File;
+import java.nio.file.Path;
 
 public class TestHelper
 {
-    public static PwmApplication makeTestPwmApplication( final File tempFolder )
+    public static PwmApplication makeTestPwmApplication( final Path tempFolder )
             throws PwmUnrecoverableException
     {
         final StoredConfiguration storedConfiguration = StoredConfigurationFactory.newConfig();
@@ -49,7 +49,7 @@ public class TestHelper
         return makeTestPwmApplication( tempFolder, appConfig );
     }
 
-    public static PwmApplication makeTestPwmApplication( final File tempFolder, final AppConfig appConfig )
+    public static PwmApplication makeTestPwmApplication( final Path tempFolder, final AppConfig appConfig )
             throws PwmUnrecoverableException
     {
         final PwmEnvironment pwmEnvironment = PwmEnvironment.builder()

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

@@ -39,7 +39,6 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.util.java.FileSystemUtility;
 import password.pwm.util.localdb.TestHelper;
 
-import java.io.File;
 import java.nio.file.Path;
 import java.util.HashMap;
 import java.util.List;
@@ -57,7 +56,7 @@ public class PasswordRuleChecksTest
     @BeforeEach
     void beforeAll() throws Exception
     {
-        final File localDbTestFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-stored-queue-test" );
+        final Path localDbTestFolder = FileSystemUtility.createDirectory( temporaryFolder, "test-stored-queue-test" );
         this.pwmApplication = TestHelper.makeTestPwmApplication( localDbTestFolder );
     }
 

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

@@ -50,7 +50,7 @@ public class RandomPasswordGeneratorTest
     public void generateRandomPasswordsTest()
             throws PwmUnrecoverableException, IOException
     {
-        final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( temporaryFolder.toFile() );
+        final PwmApplication pwmApplication = TestHelper.makeTestPwmApplication( temporaryFolder );
         final PwmDomain pwmDomain = pwmApplication.domains().get( DomainID.DOMAIN_ID_DEFAULT );
         final Map<String, String> policyMap = new HashMap<>( PwmPasswordPolicy.defaultPolicy().getPolicyMap() );
         policyMap.put( PwmPasswordRule.AllowNumeric.getKey(), "true" );

+ 1 - 1
webapp/src/main/webapp/WEB-INF/jsp/configguide-start.jsp

@@ -47,7 +47,7 @@
         <%@ include file="/WEB-INF/jsp/fragment/message.jsp" %>
         <p>
             <pwm:if test="<%=PwmIfTest.appliance%>" negate="true">
-                Application Configuration Path: <code><%=StringUtil.escapeHtml(JspUtility.getPwmRequest(pageContext).getPwmApplication().getPwmEnvironment().getApplicationPath().getAbsolutePath())%></code>
+                Application Configuration Path: <code><%=StringUtil.escapeHtml(JspUtility.getPwmRequest(pageContext).getPwmApplication().getPwmEnvironment().getApplicationPath().toString())%></code>
             </pwm:if>
         </p>
         <br/><br/>

+ 1 - 1
webapp/src/main/webapp/WEB-INF/jsp/configmanager-localdb.jsp

@@ -86,7 +86,7 @@
                             ? JspUtility.getMessage(pageContext, Display.Value_NotApplicable)
                             : localdb_pwmApplication.getLocalDB().getFileLocation() == null
                             ? JspUtility.getMessage(pageContext, Display.Value_NotApplicable)
-                            : localdb_pwmApplication.getLocalDB().getFileLocation().getAbsolutePath()
+                            : localdb_pwmApplication.getLocalDB().getFileLocation().toString()
                     %>
                 </td>
             </tr>