You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by cs...@apache.org on 2021/12/16 16:49:25 UTC
[maven-resolver] branch MRESOLVER-218-provided-checksums created (now d4c0fba)
This is an automated email from the ASF dual-hosted git repository.
cstamas pushed a change to branch MRESOLVER-218-provided-checksums
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git.
at d4c0fba [MRESOLVER-231] Make extension point where checksums are injected.
This branch includes the following new commits:
new d4c0fba [MRESOLVER-231] Make extension point where checksums are injected.
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[maven-resolver] 01/01: [MRESOLVER-231] Make extension point where checksums are injected.
Posted by cs...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
cstamas pushed a commit to branch MRESOLVER-218-provided-checksums
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit d4c0fba830be181ec00d9aad7267a9b8f3681dc5
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Thu Dec 16 17:47:59 2021 +0100
[MRESOLVER-231] Make extension point where checksums are injected.
This feature allows Resolver to get "expected" checksums ahead
of remote transport (resolution), hence, it may operate with
"good known" checksums for example (or use any other source).
---
.../connector/basic/BasicRepositoryConnector.java | 21 ++-
.../aether/connector/basic/ChecksumValidator.java | 4 +-
.../connector/basic/ChecksumValidatorTest.java | 2 +-
.../eclipse/aether/impl/guice/AetherModule.java | 16 +++
.../internal/impl/DefaultArtifactResolver.java | 31 ++++-
.../internal/impl/FileDownloadChecksumSource.java | 149 +++++++++++++++++++++
.../impl/Maven2RepositoryLayoutFactory.java | 6 +
.../internal/impl/DefaultArtifactResolverTest.java | 4 +-
.../internal/impl/TestDownloadChecksumSource.java | 66 +++++++++
.../aether/spi/connector/ArtifactDownload.java | 27 ++++
.../spi/connector/DownloadChecksumSource.java | 45 +++++++
.../aether/spi/connector/MetadataDownload.java | 27 ++++
.../spi/connector/layout/RepositoryLayout.java | 7 +
13 files changed, 395 insertions(+), 10 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 3fed9a1..e232a9a 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
@@ -231,7 +231,8 @@ final class BasicRepositoryConnector
checksums = layout.getChecksums( transfer.getMetadata(), false, location );
}
- Runnable task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy, checksums, listener );
+ Runnable task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy,
+ checksums, transfer.getProvidedChecksums(), listener );
executor.execute( errorForwarder.wrap( task ) );
}
@@ -257,7 +258,8 @@ final class BasicRepositoryConnector
checksums = layout.getChecksums( transfer.getArtifact(), false, location );
}
- task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy, checksums, listener );
+ task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy,
+ checksums, transfer.getProvidedChecksums(), listener );
}
executor.execute( errorForwarder.wrap( task ) );
}
@@ -399,13 +401,18 @@ final class BasicRepositoryConnector
private final File file;
+ private final Map<String, String> providedChecksums;
+
private final ChecksumValidator checksumValidator;
GetTaskRunner( URI path, File file, ChecksumPolicy checksumPolicy,
- List<RepositoryLayout.Checksum> checksums, TransferTransportListener<?> listener )
+ List<RepositoryLayout.Checksum> checksums, Map<String, String> providedChecksums,
+ TransferTransportListener<?> listener )
{
super( path, listener );
this.file = requireNonNull( file, "destination file cannot be null" );
+ this.providedChecksums =
+ providedChecksums == null ? Collections.emptyMap() : providedChecksums;
checksumValidator =
new ChecksumValidator( file, fileProcessor, this, checksumPolicy, safe( checksums ) );
}
@@ -416,9 +423,15 @@ final class BasicRepositoryConnector
transporter.peek( new PeekTask( path ) );
}
- public boolean fetchChecksum( URI remote, File local )
+ public boolean fetchChecksum( String algorithm, URI remote, File local )
throws Exception
{
+ String providedChecksum = providedChecksums.get( algorithm );
+ if ( providedChecksum != null )
+ {
+ fileProcessor.write( local, providedChecksum );
+ return true;
+ }
try
{
transporter.get( new GetTask( remote ).setDataFile( local ) );
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java
index 5a77bf7..92b8839 100644
--- a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java
@@ -46,7 +46,7 @@ final class ChecksumValidator
interface ChecksumFetcher
{
- boolean fetchChecksum( URI remote, File local )
+ boolean fetchChecksum( String algorithm, URI remote, File local )
throws Exception;
}
@@ -154,7 +154,7 @@ final class ChecksumValidator
File tmp = createTempFile( checksumFile );
try
{
- if ( !checksumFetcher.fetchChecksum( checksum.getLocation(), tmp ) )
+ if ( !checksumFetcher.fetchChecksum( checksum.getAlgorithm(), checksum.getLocation(), tmp ) )
{
continue;
}
diff --git a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java
index c0d1467..8db0113 100644
--- a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java
+++ b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumValidatorTest.java
@@ -127,7 +127,7 @@ public class ChecksumValidatorTest
private List<URI> fetchedFiles = new ArrayList<>();
- public boolean fetchChecksum( URI remote, File local )
+ public boolean fetchChecksum( String algorithm, URI remote, File local )
throws Exception
{
fetchedFiles.add( remote );
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java
index 9edf5f9..652ad18 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java
@@ -41,6 +41,7 @@ import org.eclipse.aether.impl.RemoteRepositoryManager;
import org.eclipse.aether.impl.RepositoryConnectorProvider;
import org.eclipse.aether.impl.RepositoryEventDispatcher;
import org.eclipse.aether.internal.impl.DefaultTrackingFileManager;
+import org.eclipse.aether.internal.impl.FileDownloadChecksumSource;
import org.eclipse.aether.internal.impl.TrackingFileManager;
import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory;
import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactorySelector;
@@ -78,6 +79,7 @@ import org.eclipse.aether.internal.impl.Maven2RepositoryLayoutFactory;
import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
import org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory;
import org.eclipse.aether.named.providers.NoopNamedLockFactory;
+import org.eclipse.aether.spi.connector.DownloadChecksumSource;
import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider;
@@ -161,6 +163,9 @@ public class AetherModule
.to( EnhancedLocalRepositoryManagerFactory.class ).in( Singleton.class );
bind( TrackingFileManager.class ).to( DefaultTrackingFileManager.class ).in( Singleton.class );
+ bind( DownloadChecksumSource.class ).annotatedWith( Names.named( FileDownloadChecksumSource.NAME ) ) //
+ .to( FileDownloadChecksumSource.class ).in( Singleton.class );
+
bind( NamedLockFactorySelector.class ).to( SimpleNamedLockFactorySelector.class ).in( Singleton.class );
bind( SyncContextFactory.class ).to( DefaultSyncContextFactory.class ).in( Singleton.class );
bind( org.eclipse.aether.impl.SyncContextFactory.class )
@@ -191,6 +196,17 @@ public class AetherModule
@Provides
@Singleton
+ Map<String, DownloadChecksumSource> provideDownloadChecksumSources(
+ @Named( FileDownloadChecksumSource.NAME ) DownloadChecksumSource fileDownloadChecksumSource
+ )
+ {
+ Map<String, DownloadChecksumSource> downloadChecksumSources = new HashMap<>();
+ downloadChecksumSources.put( FileDownloadChecksumSource.NAME, fileDownloadChecksumSource );
+ return downloadChecksumSources;
+ }
+
+ @Provides
+ @Singleton
Map<String, NameMapper> provideNameMappers(
@Named( StaticNameMapper.NAME ) NameMapper staticNameMapper,
@Named( GAVNameMapper.NAME ) NameMapper gavNameMapper,
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java
index 430ea38..5bece70 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java
@@ -27,6 +27,8 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static java.util.Objects.requireNonNull;
+
+import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
@@ -45,6 +47,7 @@ import org.eclipse.aether.impl.OfflineController;
import org.eclipse.aether.impl.RemoteRepositoryManager;
import org.eclipse.aether.impl.RepositoryConnectorProvider;
import org.eclipse.aether.impl.RepositoryEventDispatcher;
+import org.eclipse.aether.spi.connector.DownloadChecksumSource;
import org.eclipse.aether.spi.synccontext.SyncContextFactory;
import org.eclipse.aether.impl.UpdateCheck;
import org.eclipse.aether.impl.UpdateCheckManager;
@@ -106,6 +109,8 @@ public class DefaultArtifactResolver
private OfflineController offlineController;
+ private Map<String, DownloadChecksumSource> downloadChecksumSources;
+
public DefaultArtifactResolver()
{
// enables default constructor
@@ -117,7 +122,8 @@ public class DefaultArtifactResolver
VersionResolver versionResolver, UpdateCheckManager updateCheckManager,
RepositoryConnectorProvider repositoryConnectorProvider,
RemoteRepositoryManager remoteRepositoryManager, SyncContextFactory syncContextFactory,
- OfflineController offlineController )
+ OfflineController offlineController,
+ Map<String, DownloadChecksumSource> downloadChecksumSources )
{
setFileProcessor( fileProcessor );
setRepositoryEventDispatcher( repositoryEventDispatcher );
@@ -127,6 +133,7 @@ public class DefaultArtifactResolver
setRemoteRepositoryManager( remoteRepositoryManager );
setSyncContextFactory( syncContextFactory );
setOfflineController( offlineController );
+ setDownloadChecksumSources( downloadChecksumSources );
}
public void initService( ServiceLocator locator )
@@ -139,6 +146,7 @@ public class DefaultArtifactResolver
setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) );
setSyncContextFactory( locator.getService( SyncContextFactory.class ) );
setOfflineController( locator.getService( OfflineController.class ) );
+ setDownloadChecksumSources( Collections.emptyMap() );
}
/**
@@ -203,6 +211,14 @@ public class DefaultArtifactResolver
return this;
}
+ public DefaultArtifactResolver setDownloadChecksumSources(
+ Map<String, DownloadChecksumSource> downloadChecksumSources )
+ {
+ this.downloadChecksumSources = requireNonNull( downloadChecksumSources,
+ "download checksum sources cannot be null" );
+ return this;
+ }
+
public ArtifactResult resolveArtifact( RepositorySystemSession session, ArtifactRequest request )
throws ArtifactResolutionException
{
@@ -551,6 +567,19 @@ public class DefaultArtifactResolver
download.setRequestContext( item.request.getRequestContext() );
download.setListener( SafeTransferListener.wrap( session ) );
download.setTrace( item.trace );
+
+ for ( DownloadChecksumSource downloadChecksumSource : downloadChecksumSources.values() )
+ {
+ Map<String, String> providedChecksums = downloadChecksumSource.getProvidedChecksums(
+ session, group.repository, artifact );
+
+ if ( providedChecksums != null )
+ {
+ download.setProvidedChecksums( providedChecksums );
+ break;
+ }
+ }
+
if ( item.local.getFile() != null )
{
download.setFile( item.local.getFile() );
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FileDownloadChecksumSource.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FileDownloadChecksumSource.java
new file mode 100644
index 0000000..f25b640
--- /dev/null
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FileDownloadChecksumSource.java
@@ -0,0 +1,149 @@
+package org.eclipse.aether.internal.impl;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.spi.connector.DownloadChecksumSource;
+import org.eclipse.aether.spi.connector.layout.RepositoryLayout;
+import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider;
+import org.eclipse.aether.transfer.NoRepositoryLayoutException;
+import org.eclipse.aether.util.ChecksumUtils;
+import org.eclipse.aether.util.ConfigUtils;
+import org.eclipse.aether.util.artifact.ArtifactIdUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * {@link DownloadChecksumSource} that does use specified directory structure to look up checksums.
+ *
+ * @since TBD
+ */
+@Singleton
+@Named( FileDownloadChecksumSource.NAME )
+public final class FileDownloadChecksumSource
+ implements DownloadChecksumSource
+{
+ public static final String NAME = "file";
+
+ private static final String CONFIG_PROP_BASE_DIR = "aether.artifactResolver.downloadChecksumSource.file.baseDir";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger( FileDownloadChecksumSource.class );
+
+ private final RepositoryLayoutProvider repositoryLayoutProvider;
+
+ @Inject
+ public FileDownloadChecksumSource( RepositoryLayoutProvider repositoryLayoutProvider )
+ {
+ this.repositoryLayoutProvider = requireNonNull( repositoryLayoutProvider );
+ }
+
+ @Override
+ public Map<String, String> getProvidedChecksums( RepositorySystemSession session,
+ RemoteRepository remoteRepository,
+ Artifact artifact )
+ {
+ final String baseDirPath = ConfigUtils.getString( session, null, CONFIG_PROP_BASE_DIR );
+ final Path baseDir;
+ if ( baseDirPath != null )
+ {
+ baseDir = Paths.get( baseDirPath );
+ }
+ else
+ {
+ baseDir = session.getLocalRepository().getBasedir().toPath().resolve( ".checksums" );
+ }
+
+ if ( !Files.isDirectory( baseDir ) )
+ {
+ return null;
+ }
+
+ try
+ {
+ RepositoryLayout repositoryLayout = repositoryLayoutProvider
+ .newRepositoryLayout( session, remoteRepository );
+
+ HashMap<String, String> checksums = new HashMap<>();
+ for ( String algorithm : repositoryLayout.getChecksumAlgorithms() )
+ {
+ Path checksumPath = baseDir.resolve( getPathForArtifactChecksum( artifact, algorithm ) );
+ if ( Files.isReadable( checksumPath ) )
+ {
+ try
+ {
+ String checksum = ChecksumUtils.read( checksumPath.toFile() );
+ if ( checksum != null )
+ {
+ LOGGER.debug( "{} -> {}:{}", ArtifactIdUtils.toId( artifact ), algorithm, checksum );
+ checksums.put( algorithm, checksum );
+ }
+ }
+ catch ( IOException e )
+ {
+ // skip it TODO: silently?
+ }
+ }
+ }
+ return checksums.isEmpty() ? null : checksums;
+ }
+ catch ( NoRepositoryLayoutException e )
+ {
+ // fall thru TODO: silently?
+ return null;
+ }
+ }
+
+ private String getPathForArtifactChecksum( Artifact artifact, String algorithm )
+ {
+ StringBuilder path = new StringBuilder()
+ .append( artifact.getGroupId().replace( '.', '/' ) ).append( '/' )
+ .append( artifact.getArtifactId() ).append( '/' )
+ .append( artifact.getBaseVersion() ).append( '/' )
+ .append( artifact.getArtifactId() ).append( '-' )
+ .append( artifact.getVersion() );
+ if ( artifact.getClassifier().length() > 0 )
+ {
+ path.append( '-' ).append( artifact.getClassifier() );
+ }
+ if ( artifact.getExtension().length() > 0 )
+ {
+ path.append( '.' ).append( artifact.getExtension() );
+ }
+ path.append( '.' ).append( algorithm.replace( "-", "" ).toLowerCase( Locale.ENGLISH ) );
+ return path.toString();
+ }
+
+}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java
index 82933e4..6914b18 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory.java
@@ -163,6 +163,12 @@ public final class Maven2RepositoryLayoutFactory
return toUri( path.toString() );
}
+ @Override
+ public List<String> getChecksumAlgorithms()
+ {
+ return checksumsAlgorithms;
+ }
+
public List<Checksum> getChecksums( Artifact artifact, boolean upload, URI location )
{
return getChecksums( location );
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java
index 5723e7f..2a445b0 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java
@@ -25,6 +25,7 @@ import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -38,8 +39,6 @@ import org.eclipse.aether.artifact.ArtifactProperties;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.impl.UpdateCheckManager;
import org.eclipse.aether.impl.VersionResolver;
-import org.eclipse.aether.internal.impl.DefaultArtifactResolver;
-import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager;
import org.eclipse.aether.internal.test.util.TestFileProcessor;
import org.eclipse.aether.internal.test.util.TestFileUtils;
import org.eclipse.aether.internal.test.util.TestLocalRepositoryManager;
@@ -105,6 +104,7 @@ public class DefaultArtifactResolverTest
resolver.setRemoteRepositoryManager( new StubRemoteRepositoryManager() );
resolver.setSyncContextFactory( new StubSyncContextFactory() );
resolver.setOfflineController( new DefaultOfflineController() );
+ resolver.setDownloadChecksumSources( Collections.emptyMap() );
artifact = new DefaultArtifact( "gid", "aid", "", "ext", "ver" );
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/TestDownloadChecksumSource.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/TestDownloadChecksumSource.java
new file mode 100644
index 0000000..2eb92bd
--- /dev/null
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/TestDownloadChecksumSource.java
@@ -0,0 +1,66 @@
+package org.eclipse.aether.internal.impl;
+
+/*
+ * 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.
+ */
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.spi.connector.DownloadChecksumSource;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * {@link DownloadChecksumSource} that does store things in memory.
+ */
+public class TestDownloadChecksumSource
+ implements DownloadChecksumSource
+{
+ public static final String NAME = "test";
+
+ private final String algorithm;
+
+ private final Map<String, String> checksums;
+
+ public TestDownloadChecksumSource( String algorithm, Map<String, String> checksums )
+ {
+ this.algorithm = requireNonNull( algorithm );
+ this.checksums = requireNonNull( checksums );
+ }
+
+ @Override
+ public Map<String, String> getProvidedChecksums( RepositorySystemSession session,
+ RemoteRepository remoteRepository,
+ Artifact artifact )
+ {
+ String key = artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion();
+ String hash = checksums.get( key );
+ if ( hash != null )
+ {
+ return Collections.singletonMap( algorithm, hash );
+ }
+ return null;
+ }
+}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/ArtifactDownload.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/ArtifactDownload.java
index 5c1fe7f..133b459 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/ArtifactDownload.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/ArtifactDownload.java
@@ -23,6 +23,7 @@ import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import org.eclipse.aether.RequestTrace;
import org.eclipse.aether.artifact.Artifact;
@@ -43,6 +44,8 @@ public final class ArtifactDownload
private String checksumPolicy = "";
+ private Map<String, String> providedChecksums;
+
private String context = "";
private Collection<String> contexts;
@@ -139,6 +142,30 @@ public final class ArtifactDownload
}
/**
+ * Gets the provided checksums for this transfer.
+ *
+ * @return The provided checksums for this transfer, if any, or {@code null}.
+ * @since TBD
+ */
+ public Map<String, String> getProvidedChecksums()
+ {
+ return providedChecksums;
+ }
+
+ /**
+ * Sets the provided checksums for this transfer.
+ *
+ * @param providedChecksums The provided checksums, may be {@code null}.
+ * @return This transfer for chaining, never {@code null}.
+ * @since TBD
+ */
+ public ArtifactDownload setProvidedChecksums( Map<String, String> providedChecksums )
+ {
+ this.providedChecksums = providedChecksums;
+ return this;
+ }
+
+ /**
* Gets the context of this transfer.
*
* @return The context id, never {@code null}.
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/DownloadChecksumSource.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/DownloadChecksumSource.java
new file mode 100644
index 0000000..54b1c5f
--- /dev/null
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/DownloadChecksumSource.java
@@ -0,0 +1,45 @@
+package org.eclipse.aether.spi.connector;
+
+/*
+ * 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.
+ */
+
+import java.util.Map;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * Component able to provide (expected) checksums beforehand the download happens.
+ *
+ * @since TBD
+ */
+public interface DownloadChecksumSource
+{
+ /**
+ * May return the "expected" checksums for given artifact, from source other than remote repository.
+ *
+ * @param remoteRepository The remote repository artifact is about to be resolved.
+ * @param artifact The artifact about to be resolved.
+ * @return Map of "expeced" checksums, or {@code null}.
+ */
+ Map<String, String> getProvidedChecksums( RepositorySystemSession session,
+ RemoteRepository remoteRepository,
+ Artifact artifact );
+}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/MetadataDownload.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/MetadataDownload.java
index be3a2d0..9db2011 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/MetadataDownload.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/MetadataDownload.java
@@ -22,6 +22,7 @@ package org.eclipse.aether.spi.connector;
import java.io.File;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import org.eclipse.aether.RequestTrace;
import org.eclipse.aether.metadata.Metadata;
@@ -39,6 +40,8 @@ public final class MetadataDownload
private String checksumPolicy = "";
+ private Map<String, String> providedChecksums;
+
private String context = "";
private List<RemoteRepository> repositories = Collections.emptyList();
@@ -104,6 +107,30 @@ public final class MetadataDownload
}
/**
+ * Gets the provided checksums for this transfer.
+ *
+ * @return The provided checksums for this transfer, if any, or {@code null}.
+ * @since TBD
+ */
+ public Map<String, String> getProvidedChecksums()
+ {
+ return providedChecksums;
+ }
+
+ /**
+ * Sets the provided checksums for this transfer.
+ *
+ * @param providedChecksums The provided checksums, may be {@code null}.
+ * @return This transfer for chaining, never {@code null}.
+ * @since TBD
+ */
+ public MetadataDownload setProvidedChecksums( Map<String, String> providedChecksums )
+ {
+ this.providedChecksums = providedChecksums;
+ return this;
+ }
+
+ /**
* Gets the context of this transfer.
*
* @return The context id, never {@code null}.
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/layout/RepositoryLayout.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/layout/RepositoryLayout.java
index a7382b9..c5ea178 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/layout/RepositoryLayout.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/layout/RepositoryLayout.java
@@ -152,6 +152,13 @@ public interface RepositoryLayout
URI getLocation( Metadata metadata, boolean upload );
/**
+ * Returns the list of supported checksum algorithms for this remote repository layout.
+ *
+ * @return The list of algorithm names that are configured for this remote repository layout, never {@code null}.
+ */
+ List<String> getChecksumAlgorithms();
+
+ /**
* Gets the checksums files that a remote repository keeps to help detect data corruption during transfers of the
* specified artifact.
*