This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git


The following commit(s) were added to refs/heads/master by this push:
     new 43cae03d [MRESOLVER-302] Addendum (#360)
43cae03d is described below

commit 43cae03da0f877068aa4bfd6e5fd29ce2fc0eeb4
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Fri Nov 10 00:49:51 2023 +0100

    [MRESOLVER-302] Addendum (#360)
    
    Changes:
    * rename closeable session to lessen repetition in source
    * defer creation of LRM to ctor of DefaultCloseableSession
    * support chained LRM out of the box
    * make AuthenticationContext not need session (as it does not use it 
directly)
    
    ---
    
    https://issues.apache.org/jira/browse/MRESOLVER-302
---
 .../eclipse/aether/RepositorySystemSession.java    |  57 +++++-
 .../aether/repository/AuthenticationContext.java   |  12 +-
 .../aether/impl/RepositorySystemLifecycle.java     |  12 +-
 .../internal/impl/DefaultRepositorySystem.java     |   1 +
 .../impl/DefaultRepositorySystemLifecycle.java     |   8 +-
 ...emSession.java => DefaultCloseableSession.java} |  37 +++-
 .../impl/session/DefaultSessionBuilder.java        | 191 ++++-----------------
 .../repository/ChainedLocalRepositoryManager.java  |  13 ++
 pom.xml                                            |   2 +-
 src/site/markdown/configuration.md                 |   3 +-
 10 files changed, 146 insertions(+), 190 deletions(-)

diff --git 
a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java
 
b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java
index 2f1ce20c..bf7a8f52 100644
--- 
a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java
+++ 
b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java
@@ -20,6 +20,7 @@ package org.eclipse.aether;
 
 import java.io.Closeable;
 import java.io.File;
+import java.util.List;
 import java.util.Map;
 
 import org.eclipse.aether.artifact.ArtifactTypeRegistry;
@@ -55,9 +56,12 @@ public interface RepositorySystemSession {
      * Immutable session that is closeable, should be handled as a resource. 
These session instances can be
      * created with {@link SessionBuilder}.
      *
+     * @noimplement This interface is not intended to be implemented by 
clients.
+     * @noextend This interface is not intended to be extended by clients.
+     *
      * @since TBD
      */
-    interface CloseableRepositorySystemSession extends 
RepositorySystemSession, Closeable {
+    interface CloseableSession extends RepositorySystemSession, Closeable {
         /**
          * Returns the ID of this closeable session instance. Each closeable 
session has different ID, unique within
          * repository system they were created with.
@@ -88,8 +92,11 @@ public interface RepositorySystemSession {
     }
 
     /**
-     * Builder for building {@link CloseableRepositorySystemSession} 
instances. Builder instances can be created with
-     * {@link RepositorySystem#createSessionBuilder()} method.
+     * Builder for building {@link CloseableSession} instances. Builder 
instances can be created with
+     * {@link RepositorySystem#createSessionBuilder()} method. Instances are 
not thread-safe nor immutable.
+     *
+     * @noimplement This interface is not intended to be implemented by 
clients.
+     * @noextend This interface is not intended to be extended by clients.
      *
      * @since TBD
      */
@@ -386,12 +393,48 @@ public interface RepositorySystemSession {
         SessionBuilder setCache(RepositoryCache cache);
 
         /**
-         * Shortcut method to set up local repository manager.
+         * Shortcut method to set up local repository manager directly onto 
builder. There must be at least one non-null
+         * {@link File} passed in this method. In case multiple files, session 
builder will use chained local repository
+         * manager.
+         *
+         * @param baseDirectories The local repository base directories.
+         * @return This session for chaining, never {@code null}.
+         * @see #newLocalRepositoryManager(LocalRepository...)
+         */
+        SessionBuilder withLocalRepositoryBaseDirectories(File... 
baseDirectories);
+
+        /**
+         * Shortcut method to set up local repository manager directly onto 
builder. There must be at least one non-null
+         * {@link File} present in passed in list. In case multiple files, 
session builder will use chained local
+         * repository manager.
+         *
+         * @param baseDirectories The local repository base directories.
+         * @return This session for chaining, never {@code null}.
+         * @see #newLocalRepositoryManager(LocalRepository...)
+         */
+        SessionBuilder withLocalRepositoryBaseDirectories(List<File> 
baseDirectories);
+
+        /**
+         * Shortcut method to set up local repository manager directly onto 
builder. There must be at least one non-null
+         * {@link LocalRepository} passed in this method. In case multiple 
local repositories, session builder will
+         * use chained local repository manager.
+         *
+         * @param localRepositories The local repositories.
+         * @return This session for chaining, never {@code null}.
+         * @see #newLocalRepositoryManager(LocalRepository...)
+         */
+        SessionBuilder withLocalRepositories(LocalRepository... 
localRepositories);
+
+        /**
+         * Shortcut method to set up local repository manager directly onto 
builder. There must be at least one non-null
+         * {@link LocalRepository} present in passed in list. In case multiple 
local repositories, session builder will
+         * use chained local repository manager.
          *
-         * @param basedir The local repository base directory, may be {@code 
null} if none.
+         * @param localRepositories The local repositories.
          * @return This session for chaining, never {@code null}.
+         * @see #newLocalRepositoryManager(LocalRepository...)
          */
-        SessionBuilder withLocalRepository(File basedir);
+        SessionBuilder withLocalRepositories(List<LocalRepository> 
localRepositories);
 
         /**
          * Shortcut method to shallow-copy passed in session into current 
builder.
@@ -404,7 +447,7 @@ public interface RepositorySystemSession {
         /**
          * Creates a session instance.
          */
-        CloseableRepositorySystemSession build();
+        CloseableSession build();
     }
 
     /**
diff --git 
a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/AuthenticationContext.java
 
b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/AuthenticationContext.java
index feaf052f..28ea0187 100644
--- 
a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/AuthenticationContext.java
+++ 
b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/AuthenticationContext.java
@@ -142,7 +142,7 @@ public final class AuthenticationContext implements 
Closeable {
     /**
      * Gets an authentication context for the specified repository.
      *
-     * @param session The repository system session during which the 
repository is accessed, must not be {@code null}.
+     * @param session The repository system session during which the 
repository is accessed, may be {@code null}.
      * @param repository The repository for which to create an authentication 
context, must not be {@code null}.
      * @return An authentication context for the repository or {@code null} if 
no authentication is configured for it.
      */
@@ -153,7 +153,7 @@ public final class AuthenticationContext implements 
Closeable {
     /**
      * Gets an authentication context for the proxy of the specified 
repository.
      *
-     * @param session The repository system session during which the 
repository is accessed, must not be {@code null}.
+     * @param session The repository system session during which the 
repository is accessed, may be {@code null}.
      * @param repository The repository for whose proxy to create an 
authentication context, must not be {@code null}.
      * @return An authentication context for the proxy or {@code null} if no 
proxy is set or no authentication is
      *         configured for it.
@@ -173,17 +173,17 @@ public final class AuthenticationContext implements 
Closeable {
 
     private AuthenticationContext(
             RepositorySystemSession session, RemoteRepository repository, 
Proxy proxy, Authentication auth) {
-        this.session = requireNonNull(session, "repository system session 
cannot be null");
-        this.repository = repository;
+        this.session = session;
+        this.repository = requireNonNull(repository, "null repository");
         this.proxy = proxy;
         this.auth = auth;
         authData = new HashMap<>();
     }
 
     /**
-     * Gets the repository system session during which the authentication 
happens.
+     * Gets the repository system session during which the authentication 
happens (if within session).
      *
-     * @return The repository system session, never {@code null}.
+     * @return The repository system session, may be {@code null} if context 
is created outside of session.
      */
     public RepositorySystemSession getSession() {
         return session;
diff --git 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java
 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java
index 3048ed7e..37f849c5 100644
--- 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java
+++ 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java
@@ -18,7 +18,7 @@
  */
 package org.eclipse.aether.impl;
 
-import 
org.eclipse.aether.RepositorySystemSession.CloseableRepositorySystemSession;
+import org.eclipse.aether.RepositorySystemSession.CloseableSession;
 
 /**
  * Lifecycle managing component for repository system.
@@ -49,25 +49,25 @@ public interface RepositorySystemLifecycle {
      *
      * @since TBD
      */
-    void sessionStarted(CloseableRepositorySystemSession session);
+    void sessionStarted(CloseableSession session);
 
     /**
      * Signals that passed in session was ended, it will not be used anymore. 
Repository system
      * will invoke the registered handlers for this session, if any. This 
method throws if the passed in session
-     * instance was not passed to method {@link 
#sessionStarted(CloseableRepositorySystemSession)} beforehand.
+     * instance was not passed to method {@link 
#sessionStarted(CloseableSession)} beforehand.
      * <p>
      * <em>Same session instance can be ended only once.</em>
      *
      * @since TBD
      */
-    void sessionEnded(CloseableRepositorySystemSession session);
+    void sessionEnded(CloseableSession session);
 
     /**
      * Registers an "on session end" handler.
      * <p>
-     * Throws if session was not passed to {@link 
#sessionStarted(CloseableRepositorySystemSession)} beforehand.
+     * Throws if session was not passed to {@link 
#sessionStarted(CloseableSession)} beforehand.
      *
      * @since TBD
      */
-    void addOnSessionEndedHandle(CloseableRepositorySystemSession session, 
Runnable handler);
+    void addOnSessionEndedHandle(CloseableSession session, Runnable handler);
 }
diff --git 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java
 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java
index 3769bcc5..eaba5959 100644
--- 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java
+++ 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java
@@ -356,6 +356,7 @@ public class DefaultRepositorySystem implements 
RepositorySystem {
             RepositorySystemSession session, LocalRepository localRepository) {
         requireNonNull(session, "session cannot be null");
         requireNonNull(localRepository, "localRepository cannot be null");
+        validateSystem();
 
         try {
             return localRepositoryProvider.newLocalRepositoryManager(session, 
localRepository);
diff --git 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle.java
 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle.java
index 73a25c7a..2472bbb1 100644
--- 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle.java
+++ 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle.java
@@ -29,7 +29,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.aether.MultiRuntimeException;
-import 
org.eclipse.aether.RepositorySystemSession.CloseableRepositorySystemSession;
+import org.eclipse.aether.RepositorySystemSession.CloseableSession;
 import org.eclipse.aether.impl.RepositorySystemLifecycle;
 
 import static java.util.Objects.requireNonNull;
@@ -89,7 +89,7 @@ public class DefaultRepositorySystemLifecycle implements 
RepositorySystemLifecyc
     }
 
     @Override
-    public void sessionStarted(CloseableRepositorySystemSession session) {
+    public void sessionStarted(CloseableSession session) {
         requireNonNull(session, "session cannot be null");
         requireNotShutdown();
         String sessionId = session.sessionId();
@@ -102,7 +102,7 @@ public class DefaultRepositorySystemLifecycle implements 
RepositorySystemLifecyc
     }
 
     @Override
-    public void sessionEnded(CloseableRepositorySystemSession session) {
+    public void sessionEnded(CloseableSession session) {
         requireNonNull(session, "session cannot be null");
         requireNotShutdown();
         String sessionId = session.sessionId();
@@ -127,7 +127,7 @@ public class DefaultRepositorySystemLifecycle implements 
RepositorySystemLifecyc
     }
 
     @Override
-    public void addOnSessionEndedHandle(CloseableRepositorySystemSession 
session, Runnable handler) {
+    public void addOnSessionEndedHandle(CloseableSession session, Runnable 
handler) {
         requireNonNull(session, "session cannot be null");
         requireNonNull(handler, "handler cannot be null");
         requireNotShutdown();
diff --git 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/session/DefaultCloseableRepositorySystemSession.java
 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/session/DefaultCloseableSession.java
similarity index 85%
rename from 
maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/session/DefaultCloseableRepositorySystemSession.java
rename to 
maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/session/DefaultCloseableSession.java
index a9bc520d..da7b45e7 100644
--- 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/session/DefaultCloseableRepositorySystemSession.java
+++ 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/session/DefaultCloseableSession.java
@@ -19,13 +19,14 @@
 package org.eclipse.aether.internal.impl.session;
 
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.aether.RepositoryCache;
 import org.eclipse.aether.RepositoryListener;
 import org.eclipse.aether.RepositorySystem;
-import 
org.eclipse.aether.RepositorySystemSession.CloseableRepositorySystemSession;
+import org.eclipse.aether.RepositorySystemSession.CloseableSession;
 import org.eclipse.aether.SessionData;
 import org.eclipse.aether.artifact.ArtifactTypeRegistry;
 import org.eclipse.aether.collection.DependencyGraphTransformer;
@@ -43,13 +44,15 @@ import org.eclipse.aether.repository.WorkspaceReader;
 import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
 import org.eclipse.aether.resolution.ResolutionErrorPolicy;
 import org.eclipse.aether.transfer.TransferListener;
+import org.eclipse.aether.util.repository.ChainedLocalRepositoryManager;
 
 import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.toList;
 
 /**
- * A default implementation of repository system session that is immutable.
+ * A default implementation of repository system session that is immutable and 
thread-safe.
  */
-public final class DefaultCloseableRepositorySystemSession implements 
CloseableRepositorySystemSession {
+public final class DefaultCloseableSession implements CloseableSession {
     private final String sessionId;
 
     private final AtomicBoolean closed;
@@ -109,7 +112,7 @@ public final class DefaultCloseableRepositorySystemSession 
implements CloseableR
     private final RepositorySystemLifecycle repositorySystemLifecycle;
 
     @SuppressWarnings("checkstyle:parameternumber")
-    public DefaultCloseableRepositorySystemSession(
+    public DefaultCloseableSession(
             String sessionId,
             AtomicBoolean closed,
             boolean offline,
@@ -120,6 +123,7 @@ public final class DefaultCloseableRepositorySystemSession 
implements CloseableR
             String artifactUpdatePolicy,
             String metadataUpdatePolicy,
             LocalRepositoryManager localRepositoryManager,
+            List<LocalRepository> localRepositories,
             WorkspaceReader workspaceReader,
             RepositoryListener repositoryListener,
             TransferListener transferListener,
@@ -148,7 +152,6 @@ public final class DefaultCloseableRepositorySystemSession 
implements CloseableR
         this.checksumPolicy = checksumPolicy;
         this.artifactUpdatePolicy = artifactUpdatePolicy;
         this.metadataUpdatePolicy = metadataUpdatePolicy;
-        this.localRepositoryManager = requireNonNull(localRepositoryManager);
         this.workspaceReader = workspaceReader;
         this.repositoryListener = repositoryListener;
         this.transferListener = transferListener;
@@ -170,11 +173,35 @@ public final class 
DefaultCloseableRepositorySystemSession implements CloseableR
         this.repositorySystem = requireNonNull(repositorySystem);
         this.repositorySystemLifecycle = 
requireNonNull(repositorySystemLifecycle);
 
+        this.localRepositoryManager = 
getOrCreateLocalRepositoryManager(localRepositoryManager, localRepositories);
+
         if (closed == null) {
             repositorySystemLifecycle.sessionStarted(this);
         }
     }
 
+    private LocalRepositoryManager getOrCreateLocalRepositoryManager(
+            LocalRepositoryManager localRepositoryManager, 
List<LocalRepository> localRepositories) {
+        if (localRepositoryManager != null) {
+            return localRepositoryManager;
+        } else if (localRepositories != null) {
+            if (localRepositories.isEmpty()) {
+                throw new IllegalArgumentException("empty localRepositories");
+            } else if (localRepositories.size() == 1) {
+                return repositorySystem.newLocalRepositoryManager(this, 
localRepositories.get(0));
+            } else {
+                LocalRepositoryManager head =
+                        repositorySystem.newLocalRepositoryManager(this, 
localRepositories.get(0));
+                List<LocalRepositoryManager> tail = 
localRepositories.subList(1, localRepositories.size()).stream()
+                        .map(l -> 
repositorySystem.newLocalRepositoryManager(this, l))
+                        .collect(toList());
+                return new ChainedLocalRepositoryManager(head, tail, this);
+            }
+        } else {
+            throw new IllegalStateException("No local repository manager or 
local repositories set on session");
+        }
+    }
+
     @Override
     public String sessionId() {
         return sessionId;
diff --git 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/session/DefaultSessionBuilder.java
 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/session/DefaultSessionBuilder.java
index 2077d87e..70911608 100644
--- 
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/session/DefaultSessionBuilder.java
+++ 
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/session/DefaultSessionBuilder.java
@@ -19,8 +19,9 @@
 package org.eclipse.aether.internal.impl.session;
 
 import java.io.File;
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -29,6 +30,7 @@ import org.eclipse.aether.RepositoryCache;
 import org.eclipse.aether.RepositoryListener;
 import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RepositorySystemSession.CloseableSession;
 import org.eclipse.aether.RepositorySystemSession.SessionBuilder;
 import org.eclipse.aether.SessionData;
 import org.eclipse.aether.artifact.ArtifactTypeRegistry;
@@ -50,16 +52,12 @@ import org.eclipse.aether.resolution.ResolutionErrorPolicy;
 import org.eclipse.aether.transfer.TransferListener;
 
 import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.toList;
 
 /**
- * A default implementation of session builder.
- * <p>
- * Note: while this class implements {@link RepositorySystemSession}, it 
should NOT be used as such, it is just
- * an internal technical detail to allow this class some more functional 
helper abilities, like
- * {@link #withLocalRepository(File)} method is, where "chicken or egg" 
situation would be present. This class is
- * NOT immutable nor thread safe.
+ * A default implementation of session builder. Is not immutable nor 
thread-safe.
  */
-public final class DefaultSessionBuilder implements SessionBuilder, 
RepositorySystemSession {
+public final class DefaultSessionBuilder implements SessionBuilder {
     private static final MirrorSelector NULL_MIRROR_SELECTOR = r -> null;
 
     private static final ProxySelector NULL_PROXY_SELECTOR = 
RemoteRepository::getProxy;
@@ -76,8 +74,6 @@ public final class DefaultSessionBuilder implements 
SessionBuilder, RepositorySy
 
     private final AtomicBoolean closed;
 
-    private final ArrayList<Runnable> onCloseHandler;
-
     private boolean offline;
 
     private boolean ignoreArtifactDescriptorRepositories;
@@ -94,6 +90,8 @@ public final class DefaultSessionBuilder implements 
SessionBuilder, RepositorySy
 
     private LocalRepositoryManager localRepositoryManager;
 
+    private List<LocalRepository> localRepositories;
+
     private WorkspaceReader workspaceReader;
 
     private RepositoryListener repositoryListener;
@@ -137,149 +135,6 @@ public final class DefaultSessionBuilder implements 
SessionBuilder, RepositorySy
         this.repositorySystemLifecycle = 
requireNonNull(repositorySystemLifecycle);
         this.sessionId = requireNonNull(sessionId);
         this.closed = closed;
-        this.onCloseHandler = new ArrayList<>();
-    }
-
-    @Override
-    public boolean isOffline() {
-        return offline;
-    }
-
-    @Override
-    public boolean isIgnoreArtifactDescriptorRepositories() {
-        return ignoreArtifactDescriptorRepositories;
-    }
-
-    @Override
-    public ResolutionErrorPolicy getResolutionErrorPolicy() {
-        return resolutionErrorPolicy;
-    }
-
-    @Override
-    public ArtifactDescriptorPolicy getArtifactDescriptorPolicy() {
-        return artifactDescriptorPolicy;
-    }
-
-    @Override
-    public String getChecksumPolicy() {
-        return checksumPolicy;
-    }
-
-    @Override
-    public String getUpdatePolicy() {
-        return getArtifactUpdatePolicy();
-    }
-
-    @Override
-    public String getArtifactUpdatePolicy() {
-        return artifactUpdatePolicy;
-    }
-
-    @Override
-    public String getMetadataUpdatePolicy() {
-        return metadataUpdatePolicy;
-    }
-
-    @Override
-    public LocalRepository getLocalRepository() {
-        return localRepositoryManager.getRepository();
-    }
-
-    @Override
-    public LocalRepositoryManager getLocalRepositoryManager() {
-        return localRepositoryManager;
-    }
-
-    @Override
-    public WorkspaceReader getWorkspaceReader() {
-        return workspaceReader;
-    }
-
-    @Override
-    public RepositoryListener getRepositoryListener() {
-        return repositoryListener;
-    }
-
-    @Override
-    public TransferListener getTransferListener() {
-        return transferListener;
-    }
-
-    @Override
-    public Map<String, String> getSystemProperties() {
-        return systemProperties;
-    }
-
-    @Override
-    public Map<String, String> getUserProperties() {
-        return userProperties;
-    }
-
-    @Override
-    public Map<String, Object> getConfigProperties() {
-        return configProperties;
-    }
-
-    @Override
-    public MirrorSelector getMirrorSelector() {
-        return mirrorSelector;
-    }
-
-    @Override
-    public ProxySelector getProxySelector() {
-        return proxySelector;
-    }
-
-    @Override
-    public AuthenticationSelector getAuthenticationSelector() {
-        return authenticationSelector;
-    }
-
-    @Override
-    public ArtifactTypeRegistry getArtifactTypeRegistry() {
-        return artifactTypeRegistry;
-    }
-
-    @Override
-    public DependencyTraverser getDependencyTraverser() {
-        return dependencyTraverser;
-    }
-
-    @Override
-    public DependencyManager getDependencyManager() {
-        return dependencyManager;
-    }
-
-    @Override
-    public DependencySelector getDependencySelector() {
-        return dependencySelector;
-    }
-
-    @Override
-    public VersionFilter getVersionFilter() {
-        return versionFilter;
-    }
-
-    @Override
-    public DependencyGraphTransformer getDependencyGraphTransformer() {
-        return dependencyGraphTransformer;
-    }
-
-    @Override
-    public SessionData getData() {
-        return data;
-    }
-
-    @Override
-    public RepositoryCache getCache() {
-        return cache;
-    }
-
-    @Override
-    public boolean addOnSessionEndedHandler(Runnable handler) {
-        requireNonNull(handler, "null handler");
-        onCloseHandler.add(handler);
-        return true;
     }
 
     @Override
@@ -485,9 +340,26 @@ public final class DefaultSessionBuilder implements 
SessionBuilder, RepositorySy
     }
 
     @Override
-    public SessionBuilder withLocalRepository(File basedir) {
-        LocalRepository localRepository = new LocalRepository(basedir, 
"default");
-        this.localRepositoryManager = 
repositorySystem.newLocalRepositoryManager(this, localRepository);
+    public SessionBuilder withLocalRepositoryBaseDirectories(File... 
baseDirectories) {
+        return 
withLocalRepositoryBaseDirectories(Arrays.asList(baseDirectories));
+    }
+
+    @Override
+    public SessionBuilder withLocalRepositoryBaseDirectories(List<File> 
baseDirectories) {
+        requireNonNull(baseDirectories, "null baseDirectories");
+        return withLocalRepositories(
+                
baseDirectories.stream().map(LocalRepository::new).collect(toList()));
+    }
+
+    @Override
+    public SessionBuilder withLocalRepositories(LocalRepository... 
localRepositories) {
+        return withLocalRepositories(Arrays.asList(localRepositories));
+    }
+
+    @Override
+    public SessionBuilder withLocalRepositories(List<LocalRepository> 
localRepositories) {
+        requireNonNull(localRepositories, "null localRepositories");
+        this.localRepositories = localRepositories;
         return this;
     }
 
@@ -523,8 +395,8 @@ public final class DefaultSessionBuilder implements 
SessionBuilder, RepositorySy
     }
 
     @Override
-    public CloseableRepositorySystemSession build() {
-        CloseableRepositorySystemSession result = new 
DefaultCloseableRepositorySystemSession(
+    public CloseableSession build() {
+        return new DefaultCloseableSession(
                 sessionId,
                 closed,
                 offline,
@@ -535,6 +407,7 @@ public final class DefaultSessionBuilder implements 
SessionBuilder, RepositorySy
                 artifactUpdatePolicy,
                 metadataUpdatePolicy,
                 localRepositoryManager,
+                localRepositories,
                 workspaceReader,
                 repositoryListener,
                 transferListener,
@@ -554,8 +427,6 @@ public final class DefaultSessionBuilder implements 
SessionBuilder, RepositorySy
                 cache,
                 repositorySystem,
                 repositorySystemLifecycle);
-        onCloseHandler.forEach(result::addOnSessionEndedHandler);
-        return result;
     }
 
     @SuppressWarnings("checkstyle:magicnumber")
diff --git 
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/ChainedLocalRepositoryManager.java
 
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/ChainedLocalRepositoryManager.java
index d53b560f..f9a7d3ba 100644
--- 
a/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/ChainedLocalRepositoryManager.java
+++ 
b/maven-resolver-util/src/main/java/org/eclipse/aether/util/repository/ChainedLocalRepositoryManager.java
@@ -35,6 +35,7 @@ import org.eclipse.aether.repository.LocalMetadataResult;
 import org.eclipse.aether.repository.LocalRepository;
 import org.eclipse.aether.repository.LocalRepositoryManager;
 import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.util.ConfigUtils;
 
 import static java.util.Objects.requireNonNull;
 import static java.util.stream.Collectors.toList;
@@ -50,6 +51,10 @@ import static java.util.stream.Collectors.toList;
  * @since 1.9.2
  */
 public final class ChainedLocalRepositoryManager implements 
LocalRepositoryManager {
+    public static final String IGNORE_TAIL_AVAILABILITY = 
"aether.chainedLocalRepository.ignoreTailAvailability";
+
+    private static final boolean DEFAULT_IGNORE_TAIL_AVAILABILITY = true;
+
     private final LocalRepositoryManager head;
 
     private final List<LocalRepositoryManager> tail;
@@ -63,6 +68,14 @@ public final class ChainedLocalRepositoryManager implements 
LocalRepositoryManag
         this.ignoreTailAvailability = ignoreTailAvailability;
     }
 
+    public ChainedLocalRepositoryManager(
+            LocalRepositoryManager head, List<LocalRepositoryManager> tail, 
RepositorySystemSession session) {
+        this.head = requireNonNull(head, "head cannot be null");
+        this.tail = requireNonNull(tail, "tail cannot be null");
+        this.ignoreTailAvailability =
+                ConfigUtils.getBoolean(session, 
DEFAULT_IGNORE_TAIL_AVAILABILITY, IGNORE_TAIL_AVAILABILITY);
+    }
+
     @Override
     public LocalRepository getRepository() {
         return head.getRepository();
diff --git a/pom.xml b/pom.xml
index c429416c..0a0c11fc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -101,7 +101,7 @@
     <mavenVersion>4.0.0-alpha-8</mavenVersion>
     <minimalMavenBuildVersion>[3.8.8,)</minimalMavenBuildVersion>
     <!-- MRESOLVER-422: keep this in sync with Javadoc plugin configuration 
(but cannot directly, as this below is range) -->
-    <minimalJavaBuildVersion>[21.0.1,)</minimalJavaBuildVersion>
+    <minimalJavaBuildVersion>[21,)</minimalJavaBuildVersion>
     
<project.build.outputTimestamp>2023-11-02T11:01:10Z</project.build.outputTimestamp>
   </properties>
 
diff --git a/src/site/markdown/configuration.md 
b/src/site/markdown/configuration.md
index acd48b5f..e34f4e34 100644
--- a/src/site/markdown/configuration.md
+++ b/src/site/markdown/configuration.md
@@ -26,7 +26,8 @@ Option | Type | Description | Default Value | Supports Repo 
ID Suffix
 `aether.artifactResolver.postProcessor.trustedChecksums.checksumAlgorithms` | 
String | Comma-separated list of checksum algorithms with which 
`trustedChecksums` should operate (validate or record). | `"SHA-1"` | no 
 `aether.artifactResolver.postProcessor.trustedChecksums.failIfMissing` | 
boolean | Makes `trustedChecksums` fail validation if a trusted checksum for an 
artifact is missing. | `false` | no 
 `aether.artifactResolver.postProcessor.trustedChecksums.record` | boolean | 
Makes `trustedChecksums` calculate and record checksums. | `false` | no 
-`aether.artifactResolver.postProcessor.trustedChecksums.snapshots` | boolean | 
Enables or disables snapshot processing in `trustedChecksums` post processor. | 
`false` | no 
+`aether.artifactResolver.postProcessor.trustedChecksums.snapshots` | boolean | 
Enables or disables snapshot processing in `trustedChecksums` post processor. | 
`false` | no
+`aether.chainedLocalRepository.ignoreTailAvailability` | boolean | When 
chained local repository is used, whether the tail availability should be 
ignored or not. | `true` | no
 `aether.checksums.omitChecksumsForExtensions` | String | Comma-separated list 
of extensions with leading dot (example `.asc`) that should have checksums 
omitted. These are applied to sub-artifacts only. Note: to achieve 1.7.x 
`aether.checksums.forSignature=true` behaviour, pass empty string as value for 
this property. | `.asc,.sigstore` | no
 `aether.checksums.algorithms` | String | Comma-separated list of checksum 
algorithms with which checksums are validated (downloaded) and generated 
(uploaded). Resolver by default supports following algorithms: `MD5`, `SHA-1`, 
`SHA-256` and `SHA-512`. New algorithms can be added by implementing 
`ChecksumAlgorithmFactory` component. | `"SHA-1,MD5"` | yes
 `aether.conflictResolver.verbose` | boolean | Flag controlling the conflict 
resolver's verbose mode. | `false` | no

Reply via email to