Class CacheControllerImpl

java.lang.Object
org.apache.maven.buildcache.CacheControllerImpl
All Implemented Interfaces:
CacheController

@Named public class CacheControllerImpl extends Object implements CacheController
CacheControllerImpl
  • Field Details

    • ERROR_MSG_RESTORATION_OUTSIDE_PROJECT

      public static final String ERROR_MSG_RESTORATION_OUTSIDE_PROJECT
      See Also:
  • Constructor Details

  • Method Details

    • findCachedBuild

      @Nonnull public CacheResult findCachedBuild(org.apache.maven.execution.MavenSession session, org.apache.maven.project.MavenProject project, List<org.apache.maven.plugin.MojoExecution> mojoExecutions, boolean skipCache)
      Specified by:
      findCachedBuild in interface CacheController
    • restoreProjectArtifacts

      public ArtifactRestorationReport restoreProjectArtifacts(CacheResult cacheResult)
      Specified by:
      restoreProjectArtifacts in interface CacheController
    • save

      public void save(CacheResult cacheResult, List<org.apache.maven.plugin.MojoExecution> mojoExecutions, Map<String,org.apache.maven.execution.MojoExecutionEvent> executionEvents)
      Specified by:
      save in interface CacheController
    • produceDiffReport

      public void produceDiffReport(CacheResult cacheResult, Build build)
    • isForcedExecution

      public boolean isForcedExecution(org.apache.maven.project.MavenProject project, org.apache.maven.plugin.MojoExecution execution)
      Specified by:
      isForcedExecution in interface CacheController
    • saveCacheReport

      public void saveCacheReport(org.apache.maven.execution.MavenSession session)
      Specified by:
      saveCacheReport in interface CacheController
    • attachGeneratedSources

      public void attachGeneratedSources(org.apache.maven.project.MavenProject project, org.apache.maven.buildcache.CacheControllerImpl.ProjectCacheState state, long buildStartTime) throws IOException
      Throws:
      IOException
    • stagePreExistingArtifacts

      public void stagePreExistingArtifacts(org.apache.maven.execution.MavenSession session, org.apache.maven.project.MavenProject project) throws IOException
      Move pre-existing build artifacts to staging directory to prevent caching stale files.

      Artifacts Staged:

      • target/classes - Compiled main classes directory
      • target/test-classes - Compiled test classes directory
      • target/*.jar - Main project artifact (JAR/WAR files)
      • Other directories configured via attachedOutputs in cache configuration

      DESIGN RATIONALE - Staleness Detection via Staging Directory:

      This approach solves three critical problems that timestamp-based checking cannot handle:

      Problem 1: Future Timestamps from Clock Skew

      • Machine A (clock ahead at 11:00 AM) builds and caches artifacts
      • Machine B (correct clock at 10:00 AM) restores cache
      • Restored files have timestamps from the future (11:00 AM)
      • User switches branches or updates sources (sources timestamped 10:02 AM)
      • Maven incremental compiler sees: sources (10:02 AM) < classes (11:00 AM)
      • Maven skips compilation (thinks sources older than classes)
      • Wrong classes from old source version get cached!

      Problem 2: Orphaned Class Files from Deleted Sources

      • Version A has Foo.java → compiles Foo.class
      • Switch to Version B (no Foo.java)
      • Foo.class remains in target/classes (orphaned)
      • Cache miss on new version triggers mojos
      • Without protection, orphaned Foo.class gets cached
      • Future cache hits restore Foo.class (which shouldn't exist!)

      Problem 3: Stale JARs/WARs from Previous Builds

      • Yesterday: built myapp.jar on old version
      • Today: switched to new version, sources changed
      • mvn package runs (cache miss)
      • If JAR wasn't rebuilt, stale JAR could be cached

      Solution: Staging Directory Physical Separation

      • Before mojos run: Move pre-existing artifacts to target/.maven-build-cache-stash/
      • Maven sees clean target/ with no pre-existing artifacts
      • Maven compiler MUST compile (can't skip based on timestamps)
      • Fresh correct files created in target/
      • save() only sees fresh files (stale ones are in staging directory)
      • After save(): Restore artifacts from staging (delete if fresh version exists)

      Why Better Than Timestamp Checking:

      • No clock skew calculations needed
      • Physical file separation (not heuristics)
      • Forces correct incremental compilation
      • Handles interrupted builds gracefully (just delete staging directory)
      • Simpler and more robust
      • Easier cleanup - delete one directory instead of filtering files

      Interrupted Build Handling: If staging directory exists from interrupted previous run, it's deleted and recreated.

      Specified by:
      stagePreExistingArtifacts in interface CacheController
      Parameters:
      session - The Maven session
      project - The Maven project being built
      Throws:
      IOException - if file move operations fail
    • restoreStagedArtifacts

      public void restoreStagedArtifacts(org.apache.maven.execution.MavenSession session, org.apache.maven.project.MavenProject project)
      Restore artifacts from staging directory after save() completes.

      For each artifact in staging:

      • If fresh version exists in target/: Delete staged version (was rebuilt correctly)
      • If fresh version missing: Move staged version back to target/ (wasn't rebuilt, still valid)

      This ensures:

      • save() only cached fresh files (stale ones were in staging directory)
      • Developers see complete target/ directory after build
      • Incremental builds work correctly (unchanged files restored)

      Finally, deletes the staging directory.

      Specified by:
      restoreStagedArtifacts in interface CacheController
      Parameters:
      session - The Maven session
      project - The Maven project being built