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 e327728d [MRESOLVER-685] Connector pipelining (#679)
e327728d is described below
commit e327728d54ce85662af95ea1afea762c94fcb1f6
Author: Tamas Cservenak <[email protected]>
AuthorDate: Tue Apr 8 14:36:08 2025 +0200
[MRESOLVER-685] Connector pipelining (#679)
Ability to "pipe" connectors one onto another in controlled and configured
fashion.
The ide is following:
- first (actually connecting to remote) connector is chosen as today (based
on priority)
- next, new type of factories PipelinedRepositoryConnectorFactory is
ordered (by priority) and they can (but does not have to) wrap the delegate in
configured order.
Factored out existing RRF connector into new factory, and introduced
another OfflinePRCF, as so far, "resolver offline" was in fact managed at
different spots, and user was still able to circumvent offline setting. This
now connector now wraps connector and refuses going remote if session if
offline.
Vanilla resolver does this:
`offline( rrf( basic( repo ) ) )`
Ultimate goal, envision this:
`offline( mimir( sigcheck( rrf( basic( repo ) ) ) ) )`
---
https://issues.apache.org/jira/browse/MRESOLVER-685
---
.../connector/basic/BasicRepositoryConnector.java | 2 +-
.../internal/impl/DefaultOfflineController.java | 32 +++++-
.../impl/DefaultRepositoryConnectorProvider.java | 34 ++++---
...ilteringPipelineRepositoryConnectorFactory.java | 76 ++++++++++++++
.../impl/filter/FilteringRepositoryConnector.java | 2 +-
.../OfflinePipelineRepositoryConnectorFactory.java | 70 +++++++++++++
.../impl/offline/OfflineRepositoryConnector.java | 109 +++++++++++++++++++++
.../PipelineRepositoryConnectorFactory.java | 54 ++++++++++
.../aether/supplier/RepositorySystemSupplier.java | 26 ++++-
.../aether/supplier/RepositorySystemSupplier.java | 26 ++++-
src/site/markdown/configuration.md | 5 +-
11 files changed, 416 insertions(+), 20 deletions(-)
diff --git
a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java
b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java
index bcc880ad..425e887e 100644
---
a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java
+++
b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnector.java
@@ -434,7 +434,7 @@ final class BasicRepositoryConnector implements
RepositoryConnector {
@Override
public String toString() {
- return String.valueOf(repository);
+ return BasicRepositoryConnectorFactory.NAME + "( " + repository + " )";
}
abstract class TaskRunner implements Runnable {
diff --git
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultOfflineController.java
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultOfflineController.java
index 11d342fe..b639e91e 100644
---
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultOfflineController.java
+++
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultOfflineController.java
@@ -41,7 +41,7 @@ public class DefaultOfflineController implements
OfflineController {
private static final String CONFIG_PROPS_PREFIX =
ConfigurationProperties.PREFIX_AETHER + "offline.";
/**
- * Comma-separated list of protocols which are supposed to be resolved
offline.
+ * Comma-separated list of protocols which are supposed to be resolved
when session is offline.
*
* @configurationSource {@link
RepositorySystemSession#getConfigProperties()}
* @configurationType {@link java.lang.String}
@@ -49,13 +49,22 @@ public class DefaultOfflineController implements
OfflineController {
public static final String CONFIG_PROP_OFFLINE_PROTOCOLS =
CONFIG_PROPS_PREFIX + "protocols";
/**
- * Comma-separated list of hosts which are supposed to be resolved offline.
+ * Comma-separated list of hosts which are supposed to be resolved when
session is offline.
*
* @configurationSource {@link
RepositorySystemSession#getConfigProperties()}
* @configurationType {@link java.lang.String}
*/
public static final String CONFIG_PROP_OFFLINE_HOSTS = CONFIG_PROPS_PREFIX
+ "hosts";
+ /**
+ * Comma-separated list of repository IDs which are supposed to be
resolved when session is offline.
+ *
+ * @configurationSource {@link
RepositorySystemSession#getConfigProperties()}
+ * @configurationType {@link java.lang.String}
+ * @since TBD
+ */
+ public static final String CONFIG_PROP_OFFLINE_REPOSITORIES =
CONFIG_PROPS_PREFIX + "repositories";
+
private static final Pattern SEP = Pattern.compile("\\s*,\\s*");
@Override
@@ -63,7 +72,9 @@ public class DefaultOfflineController implements
OfflineController {
throws RepositoryOfflineException {
requireNonNull(session, "session cannot be null");
requireNonNull(repository, "repository cannot be null");
- if (isOfflineProtocol(session, repository) || isOfflineHost(session,
repository)) {
+ if (isOfflineProtocol(session, repository)
+ || isOfflineHost(session, repository)
+ || isOfflineRepository(session, repository)) {
return;
}
@@ -100,6 +111,21 @@ public class DefaultOfflineController implements
OfflineController {
return false;
}
+ private boolean isOfflineRepository(RepositorySystemSession session,
RemoteRepository repository) {
+ String[] repositories = getConfig(session,
CONFIG_PROP_OFFLINE_REPOSITORIES);
+ if (repositories != null) {
+ String repositoryId = repository.getId();
+ if (!repositoryId.isEmpty()) {
+ for (String r : repositories) {
+ if (r.equals(repositoryId)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
private String[] getConfig(RepositorySystemSession session, String key) {
String value = ConfigUtils.getString(session, "", key).trim();
if (value.isEmpty()) {
diff --git
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider.java
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider.java
index b2bc0ace..c655bc50 100644
---
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider.java
+++
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider.java
@@ -28,13 +28,11 @@ import java.util.List;
import java.util.Map;
import org.eclipse.aether.RepositorySystemSession;
-import org.eclipse.aether.impl.RemoteRepositoryFilterManager;
import org.eclipse.aether.impl.RepositoryConnectorProvider;
-import org.eclipse.aether.internal.impl.filter.FilteringRepositoryConnector;
import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.spi.connector.PipelineRepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.RepositoryConnector;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
-import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilter;
import org.eclipse.aether.transfer.NoRepositoryConnectorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -51,14 +49,14 @@ public class DefaultRepositoryConnectorProvider implements
RepositoryConnectorPr
private final Map<String, RepositoryConnectorFactory> connectorFactories;
- private final RemoteRepositoryFilterManager remoteRepositoryFilterManager;
+ private final Map<String, PipelineRepositoryConnectorFactory>
pipelineConnectorFactories;
@Inject
public DefaultRepositoryConnectorProvider(
Map<String, RepositoryConnectorFactory> connectorFactories,
- RemoteRepositoryFilterManager remoteRepositoryFilterManager) {
+ Map<String, PipelineRepositoryConnectorFactory>
pipelineConnectorFactories) {
this.connectorFactories =
Collections.unmodifiableMap(connectorFactories);
- this.remoteRepositoryFilterManager =
requireNonNull(remoteRepositoryFilterManager);
+ this.pipelineConnectorFactories =
Collections.unmodifiableMap(pipelineConnectorFactories);
}
@Override
@@ -78,7 +76,6 @@ public class DefaultRepositoryConnectorProvider implements
RepositoryConnectorPr
PrioritizedComponents<RepositoryConnectorFactory> factories =
PrioritizedComponents.reuseOrCreate(
session, RepositoryConnectorFactory.class, connectorFactories,
RepositoryConnectorFactory::getPriority);
- RemoteRepositoryFilter filter =
remoteRepositoryFilterManager.getRemoteRepositoryFilter(session);
List<NoRepositoryConnectorException> errors = new ArrayList<>();
for (PrioritizedComponent<RepositoryConnectorFactory> factory :
factories.getEnabled()) {
try {
@@ -94,11 +91,13 @@ public class DefaultRepositoryConnectorProvider implements
RepositoryConnectorPr
LOGGER.debug(buffer.toString());
}
- if (filter != null) {
- return new FilteringRepositoryConnector(repository,
connector, filter);
- } else {
- return connector;
+ connector = pipelineConnector(session, repository, connector);
+
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Final pipeline: {}", connector);
}
+
+ return connector;
} catch (NoRepositoryConnectorException e) {
// continue and try next factory
LOGGER.debug("Could not obtain connector factory for {}",
repository, e);
@@ -125,4 +124,17 @@ public class DefaultRepositoryConnectorProvider implements
RepositoryConnectorPr
}
throw ex;
}
+
+ protected RepositoryConnector pipelineConnector(
+ RepositorySystemSession session, RemoteRepository repository,
RepositoryConnector delegate) {
+ PrioritizedComponents<PipelineRepositoryConnectorFactory> factories =
PrioritizedComponents.reuseOrCreate(
+ session,
+ PipelineRepositoryConnectorFactory.class,
+ pipelineConnectorFactories,
+ PipelineRepositoryConnectorFactory::getPriority);
+ for (PrioritizedComponent<PipelineRepositoryConnectorFactory> factory
: factories.getEnabled()) {
+ delegate = factory.getComponent().newInstance(session, repository,
delegate);
+ }
+ return delegate;
+ }
}
diff --git
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/FilteringPipelineRepositoryConnectorFactory.java
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/FilteringPipelineRepositoryConnectorFactory.java
new file mode 100644
index 00000000..106f7068
--- /dev/null
+++
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/FilteringPipelineRepositoryConnectorFactory.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eclipse.aether.internal.impl.filter;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.impl.RemoteRepositoryFilterManager;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.spi.connector.PipelineRepositoryConnectorFactory;
+import org.eclipse.aether.spi.connector.RepositoryConnector;
+import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilter;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A filtering connector factory.
+ *
+ * @since TBD
+ */
+@Singleton
+@Named(FilteringPipelineRepositoryConnectorFactory.NAME)
+public final class FilteringPipelineRepositoryConnectorFactory implements
PipelineRepositoryConnectorFactory {
+ public static final String NAME = "rrf";
+
+ private final RemoteRepositoryFilterManager remoteRepositoryFilterManager;
+
+ /**
+ * This connector should be usually the right-most in pipeline.
+ */
+ private float priority = 10000;
+
+ @Inject
+ public
FilteringPipelineRepositoryConnectorFactory(RemoteRepositoryFilterManager
remoteRepositoryFilterManager) {
+ this.remoteRepositoryFilterManager =
requireNonNull(remoteRepositoryFilterManager);
+ }
+
+ @Override
+ public RepositoryConnector newInstance(
+ RepositorySystemSession session, RemoteRepository repository,
RepositoryConnector delegate) {
+ RemoteRepositoryFilter filter =
remoteRepositoryFilterManager.getRemoteRepositoryFilter(session);
+ if (filter != null) {
+ return new FilteringRepositoryConnector(repository, delegate,
filter);
+ } else {
+ return delegate;
+ }
+ }
+
+ @Override
+ public float getPriority() {
+ return priority;
+ }
+
+ public FilteringPipelineRepositoryConnectorFactory setPriority(float
priority) {
+ this.priority = priority;
+ return this;
+ }
+}
diff --git
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/FilteringRepositoryConnector.java
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/FilteringRepositoryConnector.java
index 0ffe4ce9..2102f905 100644
---
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/FilteringRepositoryConnector.java
+++
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/FilteringRepositoryConnector.java
@@ -104,6 +104,6 @@ public final class FilteringRepositoryConnector implements
RepositoryConnector {
@Override
public String toString() {
- return "filtered(" + delegate.toString() + ")";
+ return FilteringPipelineRepositoryConnectorFactory.NAME + "( " +
delegate.toString() + " )";
}
}
diff --git
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/offline/OfflinePipelineRepositoryConnectorFactory.java
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/offline/OfflinePipelineRepositoryConnectorFactory.java
new file mode 100644
index 00000000..a5ef87e0
--- /dev/null
+++
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/offline/OfflinePipelineRepositoryConnectorFactory.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eclipse.aether.internal.impl.offline;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.impl.OfflineController;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.spi.connector.PipelineRepositoryConnectorFactory;
+import org.eclipse.aether.spi.connector.RepositoryConnector;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Offline connector factory.
+ *
+ * @since TBD
+ */
+@Singleton
+@Named(OfflinePipelineRepositoryConnectorFactory.NAME)
+public final class OfflinePipelineRepositoryConnectorFactory implements
PipelineRepositoryConnectorFactory {
+ public static final String NAME = "offline";
+
+ private final OfflineController offlineController;
+
+ /**
+ * This connector should be usually the left-most in pipeline.
+ */
+ private float priority = 0;
+
+ @Inject
+ public OfflinePipelineRepositoryConnectorFactory(OfflineController
offlineController) {
+ this.offlineController = requireNonNull(offlineController);
+ }
+
+ @Override
+ public RepositoryConnector newInstance(
+ RepositorySystemSession session, RemoteRepository repository,
RepositoryConnector delegate) {
+ return new OfflineRepositoryConnector(session, repository,
offlineController, delegate);
+ }
+
+ @Override
+ public float getPriority() {
+ return priority;
+ }
+
+ public OfflinePipelineRepositoryConnectorFactory setPriority(float
priority) {
+ this.priority = priority;
+ return this;
+ }
+}
diff --git
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/offline/OfflineRepositoryConnector.java
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/offline/OfflineRepositoryConnector.java
new file mode 100644
index 00000000..6c280306
--- /dev/null
+++
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/offline/OfflineRepositoryConnector.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eclipse.aether.internal.impl.offline;
+
+import java.util.Collection;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.impl.OfflineController;
+import org.eclipse.aether.internal.impl.Utils;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.spi.connector.ArtifactDownload;
+import org.eclipse.aether.spi.connector.ArtifactUpload;
+import org.eclipse.aether.spi.connector.MetadataDownload;
+import org.eclipse.aether.spi.connector.MetadataUpload;
+import org.eclipse.aether.spi.connector.RepositoryConnector;
+import org.eclipse.aether.transfer.ArtifactTransferException;
+import org.eclipse.aether.transfer.MetadataTransferException;
+import org.eclipse.aether.transfer.RepositoryOfflineException;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Offline connector, that prevents ANY remote access in case session is
offline.
+ *
+ * @since TBD
+ */
+public final class OfflineRepositoryConnector implements RepositoryConnector {
+ private final RepositorySystemSession session;
+ private final RemoteRepository remoteRepository;
+ private final OfflineController offlineController;
+ private final RepositoryConnector delegate;
+
+ public OfflineRepositoryConnector(
+ RepositorySystemSession session,
+ RemoteRepository remoteRepository,
+ OfflineController offlineController,
+ RepositoryConnector delegate) {
+ this.session = requireNonNull(session);
+ this.remoteRepository = requireNonNull(remoteRepository);
+ this.offlineController = requireNonNull(offlineController);
+ this.delegate = requireNonNull(delegate);
+ }
+
+ @Override
+ public void close() {
+ delegate.close();
+ }
+
+ @Override
+ public void get(
+ Collection<? extends ArtifactDownload> artifactDownloads,
+ Collection<? extends MetadataDownload> metadataDownloads) {
+ try {
+ Utils.checkOffline(session, offlineController, remoteRepository);
+ } catch (RepositoryOfflineException e) {
+ if (artifactDownloads != null && !artifactDownloads.isEmpty()) {
+ artifactDownloads.forEach(
+ d -> d.setException(new
ArtifactTransferException(d.getArtifact(), remoteRepository, e)));
+ }
+ if (metadataDownloads != null && !metadataDownloads.isEmpty()) {
+ metadataDownloads.forEach(
+ d -> d.setException(new
MetadataTransferException(d.getMetadata(), remoteRepository, e)));
+ }
+ return;
+ }
+ delegate.get(artifactDownloads, metadataDownloads);
+ }
+
+ @Override
+ public void put(
+ Collection<? extends ArtifactUpload> artifactUploads,
+ Collection<? extends MetadataUpload> metadataUploads) {
+ try {
+ Utils.checkOffline(session, offlineController, remoteRepository);
+ } catch (RepositoryOfflineException e) {
+ if (artifactUploads != null && !artifactUploads.isEmpty()) {
+ artifactUploads.forEach(
+ d -> d.setException(new
ArtifactTransferException(d.getArtifact(), remoteRepository, e)));
+ }
+ if (metadataUploads != null && !metadataUploads.isEmpty()) {
+ metadataUploads.forEach(
+ d -> d.setException(new
MetadataTransferException(d.getMetadata(), remoteRepository, e)));
+ }
+ return;
+ }
+ delegate.put(artifactUploads, metadataUploads);
+ }
+
+ @Override
+ public String toString() {
+ return OfflinePipelineRepositoryConnectorFactory.NAME + "( " +
delegate.toString() + " )";
+ }
+}
diff --git
a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/PipelineRepositoryConnectorFactory.java
b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/PipelineRepositoryConnectorFactory.java
new file mode 100644
index 00000000..3fcd71b4
--- /dev/null
+++
b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/PipelineRepositoryConnectorFactory.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eclipse.aether.spi.connector;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * A pipeline factory to create piped repository connectors.
+ *
+ * @since TBD
+ */
+public interface PipelineRepositoryConnectorFactory {
+
+ /**
+ * Create a piped repository connector for the specified remote
repository. Typically, a factory will inspect
+ * {@link RemoteRepository#getProtocol()} and {@link
RemoteRepository#getContentType()} to determine whether it can
+ * handle a repository. This method never throws or returns {@code null},
least can do is to return the passed in
+ * delegate connector instance.
+ *
+ * @param session The repository system session from which to configure
the connector, must not be {@code null}. In
+ * particular, a connector must notify any {@link
RepositorySystemSession#getTransferListener()} set for
+ * the session and should obey the timeouts configured for the
session.
+ * @param repository The remote repository to create a connector for, must
not be {@code null}.
+ * @param delegate The delegate connector, never {@code null}. The
delegate is "right hand" connector in connector
+ * pipeline.
+ * @return The connector for the given repository, never {@code null}. If
pipeline wants to step aside, it must
+ * return the passed in delegate connector instance.
+ */
+ RepositoryConnector newInstance(
+ RepositorySystemSession session, RemoteRepository repository,
RepositoryConnector delegate);
+
+ /**
+ * The priority of this pipeline factory. Higher priority makes connector
closer to right end (tail) of pipeline
+ * (closest to delegate), while lower priority makes it closer to left
hand (head) of the pipeline.
+ */
+ float getPriority();
+}
diff --git
a/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
b/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
index 851d3f8a..4b9442e4 100644
---
a/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
+++
b/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
@@ -99,8 +99,10 @@ import
org.eclipse.aether.internal.impl.collect.DependencyCollectorDelegate;
import org.eclipse.aether.internal.impl.collect.bf.BfDependencyCollector;
import org.eclipse.aether.internal.impl.collect.df.DfDependencyCollector;
import
org.eclipse.aether.internal.impl.filter.DefaultRemoteRepositoryFilterManager;
+import
org.eclipse.aether.internal.impl.filter.FilteringPipelineRepositoryConnectorFactory;
import
org.eclipse.aether.internal.impl.filter.GroupIdRemoteRepositoryFilterSource;
import
org.eclipse.aether.internal.impl.filter.PrefixesRemoteRepositoryFilterSource;
+import
org.eclipse.aether.internal.impl.offline.OfflinePipelineRepositoryConnectorFactory;
import
org.eclipse.aether.internal.impl.resolution.TrustedChecksumsArtifactResolverPostProcessor;
import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory;
import org.eclipse.aether.internal.impl.synccontext.named.NameMapper;
@@ -121,6 +123,7 @@ import
org.eclipse.aether.spi.artifact.generator.ArtifactGeneratorFactory;
import org.eclipse.aether.spi.artifact.transformer.ArtifactTransformer;
import org.eclipse.aether.spi.checksums.ProvidedChecksumsSource;
import org.eclipse.aether.spi.checksums.TrustedChecksumsSource;
+import org.eclipse.aether.spi.connector.PipelineRepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
import
org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
@@ -703,6 +706,27 @@ public class RepositorySystemSupplier implements
Supplier<RepositorySystem> {
return result;
}
+ private Map<String, PipelineRepositoryConnectorFactory>
pipelineRepositoryConnectorFactories;
+
+ public final Map<String, PipelineRepositoryConnectorFactory>
getPipelineRepositoryConnectorFactories() {
+ checkClosed();
+ if (pipelineRepositoryConnectorFactories == null) {
+ pipelineRepositoryConnectorFactories =
createPipelineRepositoryConnectorFactories();
+ }
+ return pipelineRepositoryConnectorFactories;
+ }
+
+ protected Map<String, PipelineRepositoryConnectorFactory>
createPipelineRepositoryConnectorFactories() {
+ HashMap<String, PipelineRepositoryConnectorFactory> result = new
HashMap<>();
+ result.put(
+ FilteringPipelineRepositoryConnectorFactory.NAME,
+ new
FilteringPipelineRepositoryConnectorFactory(getRemoteRepositoryFilterManager()));
+ result.put(
+ OfflinePipelineRepositoryConnectorFactory.NAME,
+ new
OfflinePipelineRepositoryConnectorFactory(getOfflineController()));
+ return result;
+ }
+
private RepositoryConnectorProvider repositoryConnectorProvider;
public final RepositoryConnectorProvider getRepositoryConnectorProvider() {
@@ -715,7 +739,7 @@ public class RepositorySystemSupplier implements
Supplier<RepositorySystem> {
protected RepositoryConnectorProvider createRepositoryConnectorProvider() {
return new DefaultRepositoryConnectorProvider(
- getRepositoryConnectorFactories(),
getRemoteRepositoryFilterManager());
+ getRepositoryConnectorFactories(),
getPipelineRepositoryConnectorFactories());
}
private Installer installer;
diff --git
a/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
b/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
index 220ca806..ce194ebe 100644
---
a/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
+++
b/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java
@@ -103,8 +103,10 @@ import
org.eclipse.aether.internal.impl.collect.DependencyCollectorDelegate;
import org.eclipse.aether.internal.impl.collect.bf.BfDependencyCollector;
import org.eclipse.aether.internal.impl.collect.df.DfDependencyCollector;
import
org.eclipse.aether.internal.impl.filter.DefaultRemoteRepositoryFilterManager;
+import
org.eclipse.aether.internal.impl.filter.FilteringPipelineRepositoryConnectorFactory;
import
org.eclipse.aether.internal.impl.filter.GroupIdRemoteRepositoryFilterSource;
import
org.eclipse.aether.internal.impl.filter.PrefixesRemoteRepositoryFilterSource;
+import
org.eclipse.aether.internal.impl.offline.OfflinePipelineRepositoryConnectorFactory;
import
org.eclipse.aether.internal.impl.resolution.TrustedChecksumsArtifactResolverPostProcessor;
import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory;
import org.eclipse.aether.internal.impl.synccontext.named.NameMapper;
@@ -125,6 +127,7 @@ import
org.eclipse.aether.spi.artifact.generator.ArtifactGeneratorFactory;
import org.eclipse.aether.spi.artifact.transformer.ArtifactTransformer;
import org.eclipse.aether.spi.checksums.ProvidedChecksumsSource;
import org.eclipse.aether.spi.checksums.TrustedChecksumsSource;
+import org.eclipse.aether.spi.connector.PipelineRepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
import
org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
@@ -707,6 +710,27 @@ public class RepositorySystemSupplier implements
Supplier<RepositorySystem> {
return result;
}
+ private Map<String, PipelineRepositoryConnectorFactory>
pipelineRepositoryConnectorFactories;
+
+ public final Map<String, PipelineRepositoryConnectorFactory>
getPipelineRepositoryConnectorFactories() {
+ checkClosed();
+ if (pipelineRepositoryConnectorFactories == null) {
+ pipelineRepositoryConnectorFactories =
createPipelineRepositoryConnectorFactories();
+ }
+ return pipelineRepositoryConnectorFactories;
+ }
+
+ protected Map<String, PipelineRepositoryConnectorFactory>
createPipelineRepositoryConnectorFactories() {
+ HashMap<String, PipelineRepositoryConnectorFactory> result = new
HashMap<>();
+ result.put(
+ FilteringPipelineRepositoryConnectorFactory.NAME,
+ new
FilteringPipelineRepositoryConnectorFactory(getRemoteRepositoryFilterManager()));
+ result.put(
+ OfflinePipelineRepositoryConnectorFactory.NAME,
+ new
OfflinePipelineRepositoryConnectorFactory(getOfflineController()));
+ return result;
+ }
+
private RepositoryConnectorProvider repositoryConnectorProvider;
public final RepositoryConnectorProvider getRepositoryConnectorProvider() {
@@ -719,7 +743,7 @@ public class RepositorySystemSupplier implements
Supplier<RepositorySystem> {
protected RepositoryConnectorProvider createRepositoryConnectorProvider() {
return new DefaultRepositoryConnectorProvider(
- getRepositoryConnectorFactories(),
getRemoteRepositoryFilterManager());
+ getRepositoryConnectorFactories(),
getPipelineRepositoryConnectorFactories());
}
private Installer installer;
diff --git a/src/site/markdown/configuration.md
b/src/site/markdown/configuration.md
index be696288..e015543b 100644
--- a/src/site/markdown/configuration.md
+++ b/src/site/markdown/configuration.md
@@ -82,8 +82,9 @@ under the License.
| `"aether.named.ipc.nativeName"` | `String` | The name if the IPC server
native executable (without file extension like ".exe") | `"ipc-sync"` | 2.0.1
| No | Java System Properties |
| `"aether.named.ipc.nofork"` | `Boolean` | Should the IPC server not fork?
(i.e. for testing purposes) | `false` | 2.0.1 | No | Java System Properties
|
| `"aether.named.ipc.nonative"` | `Boolean` | Should the IPC server not use
native executable? | `true` | 2.0.1 | No | Java System Properties |
-| `"aether.offline.hosts"` | `String` | Comma-separated list of hosts which
are supposed to be resolved offline. | - | | No | Session Configuration |
-| `"aether.offline.protocols"` | `String` | Comma-separated list of protocols
which are supposed to be resolved offline. | - | | No | Session
Configuration |
+| `"aether.offline.hosts"` | `String` | Comma-separated list of hosts which
are supposed to be resolved when session is offline. | - | | No | Session
Configuration |
+| `"aether.offline.protocols"` | `String` | Comma-separated list of protocols
which are supposed to be accessed when session is offline. | - | | No |
Session Configuration |
+| `"aether.offline.repositories"` | `String` | Comma-separated list of
repository IDs which are supposed to be resolved when session is offline. | -
| TBD | No | Session Configuration |
| `"aether.priority.<class>"` | `Float` | The priority to use for a certain
extension class. <code><class></code> can either be the fully qualified
name or the simple name of a class. If the class name ends with Factory that
suffix could optionally be left out. This configuration is used by
<code>org.eclipse.aether.internal.impl.PrioritizedComponents</code> internal
utility to sort classes by priority. This is reusable utility (so an extension
can make use of it), but by default in [...]
| `"aether.priority.cached"` | `Boolean` | A flag indicating whether the
created ordered components should be cached in session. | `true` | 2.0.0 |
No | Session Configuration |
| `"aether.priority.implicit"` | `Boolean` | A flag indicating whether the
priorities of pluggable extensions are implicitly given by their iteration
order such that the first extension has the highest priority. If set, an
extension's built-in priority as well as any corresponding
<code>aether.priority.*</code> configuration properties are ignored when
searching for a suitable implementation among the available extensions. This
priority mode is meant for cases where the application will [...]