Class PathProcessorSupport

java.lang.Object
org.eclipse.aether.spi.io.PathProcessorSupport
All Implemented Interfaces:
PathProcessor

public class PathProcessorSupport extends Object implements PathProcessor
Utility class serving as base of PathProcessor implementations. This class can be extended or replaced (as component) when needed. Also, this class is published in Resolver implementation for path processor interface.
Since:
2.0.13
  • Field Details

    • IS_WINDOWS

      protected static final boolean IS_WINDOWS
      Logic borrowed from Commons-Lang3: we really need only this, to decide do we NIO2 file ops or not. On Windows the final move needs retry/staging logic, see retryingMove(Path, Path, StandardCopyOption[]).
    • ATOMIC_MOVE

      protected static final boolean ATOMIC_MOVE
      Escape hatch if atomic move is not desired on system we run on.
    • WINDOWS_MOVE_ATTEMPTS

      protected static final int WINDOWS_MOVE_ATTEMPTS
      The number of attempts for the final move on Windows, where the move target may be transiently locked by a virus scanner, an indexer or a concurrent reader.
    • WINDOWS_MOVE_RETRY_DELAY

      protected static final long WINDOWS_MOVE_RETRY_DELAY
      The delay in milliseconds applied between the move attempts on Windows.
    • WINDOWS_CLASSIC_COPY_FALLBACK

      protected static final boolean WINDOWS_CLASSIC_COPY_FALLBACK
      Whether to fall back to a direct (non-atomic) stream copy when all rename attempts on Windows are exhausted with AccessDeniedException due to a persistent file lock (for example an IDE holding the target .jar open). When true (the default), the installer degrades gracefully to the pre-2.0.24 behavior — the target is overwritten in-place via a stream, which on Windows succeeds even if another process holds a shared read handle. The atomicity guarantee is lost for this last-resort path, but the build succeeds. Set to false to keep the strict never-truncate contract and let the build fail with the original AccessDeniedException instead.
  • Constructor Details

  • Method Details

    • setLastModified

      public boolean setLastModified(Path path, long value) throws IOException
      Description copied from interface: PathProcessor
      Sets last modified of path in milliseconds, if exists.
      Specified by:
      setLastModified in interface PathProcessor
      Parameters:
      path - The path, may be null.
      Throws:
      IOException - If an I/O error occurs. Some exceptions/reasons of failure to set mtime may be swallowed, and can be multiple, ranging from "file not found" to cases when FS does not support the setting the mtime.
    • write

      public void write(Path target, String data) throws IOException
      Description copied from interface: PathProcessor
      Writes the given data to a file. UTF-8 is assumed as encoding for the data. Creates the necessary directories for the target file. In case of an error, the created directories will be left on the file system.
      Specified by:
      write in interface PathProcessor
      Parameters:
      target - The file to write to, must not be null. This file will be overwritten.
      data - The data to write, may be null.
      Throws:
      IOException - If an I/O error occurs.
    • write

      public void write(Path target, InputStream source) throws IOException
      Description copied from interface: PathProcessor
      Writes the given stream to a file. Creates the necessary directories for the target file. In case of an error, the created directories will be left on the file system.
      Specified by:
      write in interface PathProcessor
      Parameters:
      target - The file to write to, must not be null. This file will be overwritten.
      source - The stream to write to the file, must not be null.
      Throws:
      IOException - If an I/O error occurs.
    • writeWithBackup

      public void writeWithBackup(Path target, String data) throws IOException
      Description copied from interface: PathProcessor
      Writes the given data to a file. UTF-8 is assumed as encoding for the data. Creates the necessary directories for the target file. In case of an error, the created directories will be left on the file system.
      Specified by:
      writeWithBackup in interface PathProcessor
      Parameters:
      target - The file to write to, must not be null. This file will be overwritten.
      data - The data to write, may be null.
      Throws:
      IOException - If an I/O error occurs.
    • writeWithBackup

      public void writeWithBackup(Path target, InputStream source) throws IOException
      Description copied from interface: PathProcessor
      Writes the given stream to a file. Creates the necessary directories for the target file. In case of an error, the created directories will be left on the file system.
      Specified by:
      writeWithBackup in interface PathProcessor
      Parameters:
      target - The file to write to, must not be null. This file will be overwritten.
      source - The stream to write to the file, must not be null.
      Throws:
      IOException - If an I/O error occurs.
    • writeFile

      public void writeFile(Path target, PathProcessorSupport.FileWriter writer, boolean doBackup) throws IOException
      Utility method to write out file to disk in "atomic" manner, with optional backups (".bak") if needed. This ensures that no other thread or process will be able to read not fully written files. Finally, this method may create the needed parent directories, if the passed in target parents does not exist.
      Parameters:
      target - that is the target file (must be an existing or non-existing file, the path must have parent)
      writer - the writer that will accept a Path to write content to
      doBackup - if true, and target file is about to be overwritten, a ".bak" file with old contents will be created/overwritten
      Throws:
      IOException - if at any step IO problem occurs
    • copy

      public long copy(Path source, Path target, PathProcessor.ProgressListener listener) throws IOException
      Description copied from interface: PathProcessor
      Copies the specified source file to the given target file. Creates the necessary directories for the target file. In case of an error, the created directories will be left on the file system.
      Specified by:
      copy in interface PathProcessor
      Parameters:
      source - The file to copy from, must not be null.
      target - The file to copy to, must not be null.
      listener - The listener to notify about the copy progress, may be null.
      Returns:
      The number of copied bytes.
      Throws:
      IOException - If an I/O error occurs.
    • move

      public void move(Path source, Path target) throws IOException
      Description copied from interface: PathProcessor
      Moves the specified source file to the given target file. If the target file already exists, it is overwritten. Creates the necessary directories for the target file. In case of an error, the created directories will be left on the file system.
      Specified by:
      move in interface PathProcessor
      Parameters:
      source - The file to move from, must not be null.
      target - The file to move to, must not be null.
      Throws:
      IOException - If an I/O error occurs.
    • newTempFile

      Description copied from interface: PathProcessor
      Creates a PathProcessor.TempFile instance and backing temporary file on file system. It will be located in the default temporary-file directory. Returned instance should be handled in try-with-resource construct and created temp file is removed (if exists) when returned instance is closed.

      This method uses Files.createTempFile(String, String, java.nio.file.attribute.FileAttribute[]) to create the temporary file on file system.

      Specified by:
      newTempFile in interface PathProcessor
      Throws:
      IOException
    • newTempFile

      Description copied from interface: PathProcessor
      Creates a PathProcessor.CollocatedTempFile instance for given file without backing file. The path will be located in same directory where given file is, and will reuse its name for generated (randomized) name. Returned instance should be handled in try-with-resource and created temp path is removed (if exists) when returned instance is closed. The PathProcessor.CollocatedTempFile.move() makes possible to atomically replace passed in file with the processed content written into a file backing the PathProcessor.CollocatedTempFile instance.

      The file nor it's parent directories have to exist. The parent directories are created if needed.

      This method uses Path.resolve(String) to create the temporary file path in passed in file parent directory, but it does NOT create backing file on file system.

      Specified by:
      newTempFile in interface PathProcessor
      Throws:
      IOException
    • retryingMove

      protected void retryingMove(Path source, Path target, StandardCopyOption[] copyOptions) throws IOException
      Moves the source file to the target path, preferring atomic rename over truncating the target in place.

      Normally the content visible at the target path is either the old file or the complete new file, never a partially written one. This method attempts the rename a bounded number of times (WINDOWS_MOVE_ATTEMPTS; file locking by virus scanners, indexers or concurrent readers is transient on Windows), and if the file system refuses an atomic move (for example when source and target are on different stores), the source is first staged into a collocated temporary file next to the target and then renamed into place.

      Last-resort fallback (Windows / IDE lock): When all rename attempts are exhausted with AccessDeniedException — typically because an IDE such as IntelliJ keeps the target .jar open continuously — and WINDOWS_CLASSIC_COPY_FALLBACK is true (the default), the method falls back to a direct stream copy over the target path (classicCopy(Path, Path)). On Windows, opening a file for writing via a stream succeeds even if another process holds a shared read handle, so the build completes. The atomicity guarantee is lost for this edge case: a concurrent reader may observe a partially written file. Set the system property org.eclipse.aether.spi.io.PathProcessor.WINDOWS_CLASSIC_COPY_FALLBACK=false to disable this fallback and propagate the AccessDeniedException instead.

      Throws:
      IOException
    • fileSystemMove

      protected void fileSystemMove(Path source, Path target, StandardCopyOption... copyOptions) throws IOException
      Throws:
      IOException
    • isClassicCopyFallbackEnabled

      protected boolean isClassicCopyFallbackEnabled()
      Returns whether the classic-copy fallback is enabled. Exposed as a protected method to allow subclasses (and tests) to override the behavior controlled by WINDOWS_CLASSIC_COPY_FALLBACK.
    • classicCopy

      protected void classicCopy(Path source, Path target) throws IOException
      Pre-NIO2 way to copy files. Opens the target with truncation; normally callers stage into a temporary file and rename into place to avoid exposing partially written content. Used as a last resort on Windows when all atomic rename attempts are exhausted due to a persistent file lock (see retryingMove(Path, Path, StandardCopyOption[])).
      Throws:
      IOException