Class AbstractArchiveFileAccess

java.lang.Object
dev.jcputney.elearning.parser.api.AbstractArchiveFileAccess
All Implemented Interfaces:
FileAccess, AutoCloseable
Direct Known Subclasses:
InMemoryFileAccess, ZipFileAccess

public abstract class AbstractArchiveFileAccess extends Object implements FileAccess, AutoCloseable
Abstract base class for FileAccess implementations that work with archive-like storage structures (ZIP files, in-memory archives, cloud storage buckets) where root path detection and path normalization are needed.

This class provides common functionality for:

  • Automatic detection of root directories within archive structures
  • Path conversion between storage paths and relative paths
  • Consistent handling of single-root vs multi-root archives

Usage Pattern: Subclasses should:

  1. Call the constructor after loading file metadata
  2. Implement getStorageFilePaths() to provide file paths from storage
  3. Use stripRootPath(String) when returning paths to callers
  4. Use FileAccess.fullPath(String) when accessing storage with caller-provided paths

Root Path Detection: This class automatically detects if all files in the archive share a common root directory. For example, if a ZIP contains:

   module-v1.0/imsmanifest.xml
   module-v1.0/content/page1.html
   module-v1.0/resources/style.css
 
The root path will be detected as "module-v1.0", and stripRootPath(String) will convert storage paths to relative paths like "imsmanifest.xml", "content/page1.html", etc.
See Also:
  • Field Details

    • rootPath

      protected String rootPath
      The detected root path within the archive. Empty string if files are at the root level or if multiple top-level directories exist.
  • Constructor Details

    • AbstractArchiveFileAccess

      protected AbstractArchiveFileAccess()
      Constructs an AbstractArchiveFileAccess. Subclasses must call initializeRootPath() after loading file metadata.
  • Method Details

    • getRootPath

      public String getRootPath()
      Gets the detected root path within the archive.
      Specified by:
      getRootPath in interface FileAccess
      Returns:
      The root path, or an empty string if files are at the root level.
    • close

      public void close() throws IOException
      Default implementation of close for archive-based implementations. Subclasses that manage external resources (like file handles) should override this.
      Specified by:
      close in interface AutoCloseable
      Throws:
      IOException - if an error occurs while closing resources
    • initializeRootPath

      protected final void initializeRootPath()
      Initializes the root path by detecting it from storage file paths. Subclasses must call this method after loading their file metadata.
    • getStorageFilePaths

      protected abstract Iterable<String> getStorageFilePaths()
      Template method that subclasses must implement to provide all file paths from storage. These paths should be in their original storage format (e.g., with root prefix if present).

      This method is called during construction to detect the root path.

      Returns:
      An iterable of all file paths in their storage format
    • detectRootPath

      protected String detectRootPath()
      Detects the common root directory by analyzing file paths from storage.

      This method determines if all files in the archive are contained within a single top-level directory. If so, it returns that directory name as the root path. Otherwise, it returns an empty string, indicating files are at the root level or span multiple top-level directories.

      Detection Algorithm:

      1. Extract the first path component from each file path
      2. If all files share the same first component, that becomes the root path
      3. If files have different first components, or are at the root level, return empty string
      Returns:
      The detected root directory name, or empty string if no common root exists
    • normalizeDirectory

      protected String normalizeDirectory(String dir)
      Normalizes a directory path by ensuring it ends with a slash.
      Parameters:
      dir - The directory path to normalize.
      Returns:
      The normalized directory path ending with "/".
    • checkForRootPath

      protected boolean checkForRootPath(Set<String> topLevelDirs, String entryName)
      Checks if a file entry represents a root-level directory or if multiple top-level directories are present in the provided set.
      Parameters:
      topLevelDirs - A set of strings representing the top-level directories encountered so far. This set is modified by the method to add new entries if applicable.
      entryName - The name of the file entry to evaluate, potentially containing a directory path.
      Returns:
      True if the file entry is at the root level or if more than one top-level directory is present; false otherwise.
    • stripRootPath

      protected String stripRootPath(String storagePath)
      Strips the root path prefix from an internal storage path to create a relative path.

      This is the inverse operation of FileAccess.fullPath(String).

      Example: If rootPath="module-root" and storagePath="module-root/page.html", this method returns "page.html".

      Parameters:
      storagePath - The absolute storage path to convert to a relative path.
      Returns:
      The path relative to rootPath, or the original path if no root prefix exists.
      Throws:
      IllegalArgumentException - if storagePath is null