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 2022/01/31 11:26:00 UTC
[maven-resolver] branch master updated: [MRESOLVER-234] Provided checksums (#141)
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 e61c081 [MRESOLVER-234] Provided checksums (#141)
e61c081 is described below
commit e61c081d446acaa9547bb7aff57d28bc8498524d
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Mon Jan 31 12:25:56 2022 +0100
[MRESOLVER-234] Provided checksums (#141)
This feature allows Resolver to get "provided" 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 | 28 +++-
.../basic/BasicRepositoryConnectorFactory.java | 33 +++-
.../aether/connector/basic/ChecksumValidator.java | 49 ++++--
.../connector/basic/ChecksumValidatorTest.java | 45 +++---
.../basic/TestChecksumAlgorithmSelector.java | 2 +-
.../eclipse/aether/impl/guice/AetherModule.java | 16 ++
.../internal/impl/AbstractChecksumPolicy.java | 8 +-
.../internal/impl/FileProvidedChecksumsSource.java | 169 +++++++++++++++++++++
.../impl/Maven2RepositoryLayoutFactory.java | 5 +-
.../DefaultChecksumAlgorithmFactorySelector.java | 15 +-
.../internal/impl/DefaultArtifactResolverTest.java | 2 -
.../internal/impl/FailChecksumPolicyTest.java | 21 ++-
.../impl/FileProvidedChecksumsSourceTest.java | 107 +++++++++++++
.../impl/Maven2RepositoryLayoutFactoryTest.java | 7 +-
.../internal/impl/WarnChecksumPolicyTest.java | 12 +-
.../checksum/ChecksumAlgorithmFactorySelector.java | 11 +-
.../spi/connector/checksum/ChecksumPolicy.java | 62 ++++++--
.../checksum/ProvidedChecksumsSource.java | 47 ++++++
.../spi/connector/layout/RepositoryLayout.java | 6 +-
.../aether/spi/connector/transport/GetTask.java | 10 +-
20 files changed, 560 insertions(+), 95 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 a338c6d..c761941 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
@@ -50,6 +50,7 @@ import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmHelper;
import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy;
import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
+import org.eclipse.aether.spi.connector.checksum.ProvidedChecksumsSource;
import org.eclipse.aether.spi.connector.layout.RepositoryLayout;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider;
import org.eclipse.aether.spi.connector.transport.GetTask;
@@ -88,6 +89,8 @@ final class BasicRepositoryConnector
private static final Logger LOGGER = LoggerFactory.getLogger( BasicRepositoryConnector.class );
+ private final Map<String, ProvidedChecksumsSource> providedChecksumsSources;
+
private final FileProcessor fileProcessor;
private final RemoteRepository repository;
@@ -117,7 +120,8 @@ final class BasicRepositoryConnector
TransporterProvider transporterProvider,
RepositoryLayoutProvider layoutProvider,
ChecksumPolicyProvider checksumPolicyProvider,
- FileProcessor fileProcessor )
+ FileProcessor fileProcessor,
+ Map<String, ProvidedChecksumsSource> providedChecksumsSources )
throws NoRepositoryConnectorException
{
try
@@ -141,6 +145,7 @@ final class BasicRepositoryConnector
this.session = session;
this.repository = repository;
this.fileProcessor = fileProcessor;
+ this.providedChecksumsSources = providedChecksumsSources;
maxThreads = ConfigUtils.getInteger( session, 5, CONFIG_PROP_THREADS, "maven.artifact.threads" );
smartChecksums = ConfigUtils.getBoolean( session, true, CONFIG_PROP_SMART_CHECKSUMS );
@@ -239,12 +244,25 @@ final class BasicRepositoryConnector
}
Runnable task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy,
- checksumLocations, listener );
+ checksumLocations, null, listener );
executor.execute( errorForwarder.wrap( task ) );
}
for ( ArtifactDownload transfer : safe( artifactDownloads ) )
{
+ Map<String, String> providedChecksums = Collections.emptyMap();
+ for ( ProvidedChecksumsSource providedChecksumsSource : providedChecksumsSources.values() )
+ {
+ Map<String, String> provided = providedChecksumsSource.getProvidedArtifactChecksums(
+ session, transfer, layout.getChecksumAlgorithmFactories() );
+
+ if ( provided != null )
+ {
+ providedChecksums = provided;
+ break;
+ }
+ }
+
URI location = layout.getLocation( transfer.getArtifact(), false );
TransferResource resource = newTransferResource( location, transfer.getFile(), transfer.getTrace() );
@@ -265,7 +283,8 @@ final class BasicRepositoryConnector
checksumLocations = layout.getChecksumLocations( transfer.getArtifact(), false, location );
}
- task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy, checksumLocations, listener );
+ task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy,
+ checksumLocations, providedChecksums, listener );
}
executor.execute( errorForwarder.wrap( task ) );
}
@@ -416,12 +435,13 @@ final class BasicRepositoryConnector
GetTaskRunner( URI path, File file, ChecksumPolicy checksumPolicy,
List<RepositoryLayout.ChecksumLocation> checksumLocations,
+ Map<String, String> providedChecksums,
TransferTransportListener<?> listener )
{
super( path, listener );
this.file = requireNonNull( file, "destination file cannot be null" );
checksumValidator = new ChecksumValidator( file, fileProcessor, this,
- checksumPolicy, safe( checksumLocations ) );
+ checksumPolicy, providedChecksums, safe( checksumLocations ) );
}
@Override
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java
index aa747a9..280df6d 100644
--- a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java
@@ -19,6 +19,9 @@ package org.eclipse.aether.connector.basic;
* under the License.
*/
+import java.util.Collections;
+import java.util.Map;
+
import javax.inject.Inject;
import javax.inject.Named;
@@ -29,6 +32,7 @@ import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.spi.connector.RepositoryConnector;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
+import org.eclipse.aether.spi.connector.checksum.ProvidedChecksumsSource;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider;
import org.eclipse.aether.spi.connector.transport.TransporterProvider;
import org.eclipse.aether.spi.io.FileProcessor;
@@ -53,6 +57,8 @@ public final class BasicRepositoryConnectorFactory
private FileProcessor fileProcessor;
+ private Map<String, ProvidedChecksumsSource> providedChecksumsSources;
+
private float priority;
/**
@@ -66,13 +72,17 @@ public final class BasicRepositoryConnectorFactory
}
@Inject
- BasicRepositoryConnectorFactory( TransporterProvider transporterProvider, RepositoryLayoutProvider layoutProvider,
- ChecksumPolicyProvider checksumPolicyProvider, FileProcessor fileProcessor )
+ BasicRepositoryConnectorFactory( TransporterProvider transporterProvider,
+ RepositoryLayoutProvider layoutProvider,
+ ChecksumPolicyProvider checksumPolicyProvider,
+ FileProcessor fileProcessor,
+ Map<String, ProvidedChecksumsSource> providedChecksumsSources )
{
setTransporterProvider( transporterProvider );
setRepositoryLayoutProvider( layoutProvider );
setChecksumPolicyProvider( checksumPolicyProvider );
setFileProcessor( fileProcessor );
+ setProvidedChecksumSources( providedChecksumsSources );
}
public void initService( ServiceLocator locator )
@@ -81,6 +91,7 @@ public final class BasicRepositoryConnectorFactory
setRepositoryLayoutProvider( locator.getService( RepositoryLayoutProvider.class ) );
setChecksumPolicyProvider( locator.getService( ChecksumPolicyProvider.class ) );
setFileProcessor( locator.getService( FileProcessor.class ) );
+ setProvidedChecksumSources( Collections.emptyMap() );
}
/**
@@ -132,6 +143,22 @@ public final class BasicRepositoryConnectorFactory
return this;
}
+ /**
+ * Sets the provided checksum sources to use for this component.
+ *
+ * @param providedChecksumsSources The provided checksum sources to use, must not be {@code null}.
+ * @return This component for chaining, never {@code null}.
+ * @since 1.8.0
+ */
+ public BasicRepositoryConnectorFactory setProvidedChecksumSources(
+ Map<String, ProvidedChecksumsSource> providedChecksumsSources )
+ {
+ this.providedChecksumsSources = requireNonNull(
+ providedChecksumsSources, "provided checksum sources cannot be null"
+ );
+ return this;
+ }
+
public float getPriority()
{
return priority;
@@ -156,7 +183,7 @@ public final class BasicRepositoryConnectorFactory
requireNonNull( "repository", "repository cannot be null" );
return new BasicRepositoryConnector( session, repository, transporterProvider, layoutProvider,
- checksumPolicyProvider, fileProcessor );
+ checksumPolicyProvider, fileProcessor, providedChecksumsSources );
}
}
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 2e4e3b7..cd2ddf7 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
@@ -30,6 +30,7 @@ import java.util.UUID;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy;
+import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy.ChecksumKind;
import org.eclipse.aether.spi.connector.layout.RepositoryLayout.ChecksumLocation;
import org.eclipse.aether.spi.io.FileProcessor;
import org.eclipse.aether.transfer.ChecksumFailureException;
@@ -45,6 +46,10 @@ final class ChecksumValidator
interface ChecksumFetcher
{
+ /**
+ * Fetches the checksums from remote location into provided local file. The checksums fetched in this way
+ * are of kind {@link ChecksumKind#REMOTE_EXTERNAL}.
+ */
boolean fetchChecksum( URI remote, File local )
throws Exception;
@@ -62,6 +67,8 @@ final class ChecksumValidator
private final ChecksumPolicy checksumPolicy;
+ private final Map<String, String> providedChecksums;
+
private final Collection<ChecksumLocation> checksumLocations;
private final Map<File, Object> checksumFiles;
@@ -70,6 +77,7 @@ final class ChecksumValidator
FileProcessor fileProcessor,
ChecksumFetcher checksumFetcher,
ChecksumPolicy checksumPolicy,
+ Map<String, String> providedChecksums,
Collection<ChecksumLocation> checksumLocations )
{
this.dataFile = dataFile;
@@ -77,6 +85,7 @@ final class ChecksumValidator
this.fileProcessor = fileProcessor;
this.checksumFetcher = checksumFetcher;
this.checksumPolicy = checksumPolicy;
+ this.providedChecksums = providedChecksums;
this.checksumLocations = checksumLocations;
this.checksumFiles = new HashMap<>();
}
@@ -90,14 +99,20 @@ final class ChecksumValidator
return null;
}
- public void validate( Map<String, ?> actualChecksums, Map<String, ?> inlinedChecksums )
+ public void validate( Map<String, ?> actualChecksums, Map<String, ?> includedChecksums )
throws ChecksumFailureException
{
if ( checksumPolicy == null )
{
return;
}
- if ( inlinedChecksums != null && validateInlinedChecksums( actualChecksums, inlinedChecksums ) )
+ if ( providedChecksums != null
+ && validateChecksums( actualChecksums, ChecksumKind.PROVIDED, providedChecksums ) )
+ {
+ return;
+ }
+ if ( includedChecksums != null
+ && validateChecksums( actualChecksums, ChecksumKind.REMOTE_INCLUDED, includedChecksums ) )
{
return;
}
@@ -108,10 +123,10 @@ final class ChecksumValidator
checksumPolicy.onNoMoreChecksums();
}
- private boolean validateInlinedChecksums( Map<String, ?> actualChecksums, Map<String, ?> inlinedChecksums )
+ private boolean validateChecksums( Map<String, ?> actualChecksums, ChecksumKind kind, Map<String, ?> checksums )
throws ChecksumFailureException
{
- for ( Map.Entry<String, ?> entry : inlinedChecksums.entrySet() )
+ for ( Map.Entry<String, ?> entry : checksums.entrySet() )
{
String algo = entry.getKey();
Object calculated = actualChecksums.get( algo );
@@ -135,10 +150,10 @@ final class ChecksumValidator
if ( !isEqualChecksum( expected, actual ) )
{
- checksumPolicy.onChecksumMismatch( factory.getName(), ChecksumPolicy.KIND_UNOFFICIAL,
+ checksumPolicy.onChecksumMismatch( factory.getName(), kind,
new ChecksumFailureException( expected, actual ) );
}
- else if ( checksumPolicy.onChecksumMatch( factory.getName(), ChecksumPolicy.KIND_UNOFFICIAL ) )
+ else if ( checksumPolicy.onChecksumMatch( factory.getName(), kind ) )
{
return true;
}
@@ -156,7 +171,9 @@ final class ChecksumValidator
if ( calculated instanceof Exception )
{
checksumPolicy.onChecksumError(
- factory.getName(), 0, new ChecksumFailureException( (Exception) calculated ) );
+ factory.getName(), ChecksumKind.REMOTE_EXTERNAL,
+ new ChecksumFailureException( (Exception) calculated )
+ );
continue;
}
try
@@ -165,14 +182,18 @@ final class ChecksumValidator
File tmp = createTempFile( checksumFile );
try
{
- if ( !checksumFetcher.fetchChecksum( checksumLocation.getLocation(), tmp ) )
+ if ( !checksumFetcher.fetchChecksum(
+ checksumLocation.getLocation(), tmp
+ ) )
{
continue;
}
}
catch ( Exception e )
{
- checksumPolicy.onChecksumError( factory.getName(), 0, new ChecksumFailureException( e ) );
+ checksumPolicy.onChecksumError(
+ factory.getName(), ChecksumKind.REMOTE_EXTERNAL, new ChecksumFailureException( e )
+ );
continue;
}
@@ -183,16 +204,20 @@ final class ChecksumValidator
if ( !isEqualChecksum( expected, actual ) )
{
checksumPolicy.onChecksumMismatch(
- factory.getName(), 0, new ChecksumFailureException( expected, actual ) );
+ factory.getName(), ChecksumKind.REMOTE_EXTERNAL,
+ new ChecksumFailureException( expected, actual )
+ );
}
- else if ( checksumPolicy.onChecksumMatch( factory.getName(), 0 ) )
+ else if ( checksumPolicy.onChecksumMatch( factory.getName(), ChecksumKind.REMOTE_EXTERNAL ) )
{
return true;
}
}
catch ( IOException e )
{
- checksumPolicy.onChecksumError( factory.getName(), 0, new ChecksumFailureException( e ) );
+ checksumPolicy.onChecksumError(
+ factory.getName(), ChecksumKind.REMOTE_EXTERNAL, new ChecksumFailureException( e )
+ );
}
}
return false;
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 aac3c1b..5e4f121 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
@@ -57,9 +57,9 @@ public class ChecksumValidatorTest
private Object conclusion;
@Override
- public boolean onChecksumMatch( String algorithm, int kind )
+ public boolean onChecksumMatch( String algorithm, ChecksumKind kind )
{
- callbacks.add( String.format( "match(%s, %04x)", algorithm, kind ) );
+ callbacks.add( String.format( "match(%s, %s)", algorithm, kind ) );
if ( inspectAll )
{
if ( conclusion == null )
@@ -72,10 +72,10 @@ public class ChecksumValidatorTest
}
@Override
- public void onChecksumMismatch( String algorithm, int kind, ChecksumFailureException exception )
+ public void onChecksumMismatch( String algorithm, ChecksumKind kind, ChecksumFailureException exception )
throws ChecksumFailureException
{
- callbacks.add( String.format( "mismatch(%s, %04x)", algorithm, kind ) );
+ callbacks.add( String.format( "mismatch(%s, %s)", algorithm, kind ) );
if ( inspectAll )
{
conclusion = exception;
@@ -85,9 +85,9 @@ public class ChecksumValidatorTest
}
@Override
- public void onChecksumError( String algorithm, int kind, ChecksumFailureException exception )
+ public void onChecksumError( String algorithm, ChecksumKind kind, ChecksumFailureException exception )
{
- callbacks.add( String.format( "error(%s, %04x, %s)", algorithm, kind, exception.getCause().getMessage() ) );
+ callbacks.add( String.format( "error(%s, %s, %s)", algorithm, kind, exception.getCause().getMessage() ) );
}
@Override
@@ -201,7 +201,12 @@ public class ChecksumValidatorTest
private ChecksumValidator newValidator( String... factories )
{
- return new ChecksumValidator( dataFile, new TestFileProcessor(), fetcher, policy, newChecksums( factories ) );
+ return newValidator( null, factories );
+ }
+
+ private ChecksumValidator newValidator( Map<String, String> providedChecksums, String... factories )
+ {
+ return new ChecksumValidator( dataFile, new TestFileProcessor(), fetcher, policy, providedChecksums, newChecksums( factories ) );
}
private Map<String, ?> checksums( String... algoDigestPairs )
@@ -251,7 +256,7 @@ public class ChecksumValidatorTest
fetcher.mock( SHA1, "foo" );
validator.validate( checksums( SHA1, "foo" ), null );
fetcher.assertFetchedFiles( SHA1 );
- policy.assertCallbacks( "match(SHA-1, 0000)" );
+ policy.assertCallbacks( "match(SHA-1, REMOTE_EXTERNAL)" );
}
@Test
@@ -271,7 +276,7 @@ public class ChecksumValidatorTest
assertTrue( e.isRetryWorthy() );
}
fetcher.assertFetchedFiles( SHA1 );
- policy.assertCallbacks( "mismatch(SHA-1, 0000)" );
+ policy.assertCallbacks( "mismatch(SHA-1, REMOTE_EXTERNAL)" );
}
@Test
@@ -284,7 +289,7 @@ public class ChecksumValidatorTest
fetcher.mock( MD5, "bar" );
validator.validate( checksums( SHA1, "foo", MD5, "bar" ), null );
fetcher.assertFetchedFiles( SHA1, MD5 );
- policy.assertCallbacks( "match(SHA-1, 0000)", "match(MD5, 0000)", "noMore()" );
+ policy.assertCallbacks( "match(SHA-1, REMOTE_EXTERNAL)", "match(MD5, REMOTE_EXTERNAL)", "noMore()" );
}
@Test
@@ -306,21 +311,23 @@ public class ChecksumValidatorTest
assertTrue( e.isRetryWorthy() );
}
fetcher.assertFetchedFiles( SHA1, MD5 );
- policy.assertCallbacks( "mismatch(SHA-1, 0000)", "match(MD5, 0000)", "noMore()" );
+ policy.assertCallbacks( "mismatch(SHA-1, REMOTE_EXTERNAL)", "match(MD5, REMOTE_EXTERNAL)", "noMore()" );
}
@Test
- public void testValidate_InlinedBeforeExternal()
+ public void testValidate_IncludedBeforeExternal()
throws Exception
{
policy.inspectAll = true;
- ChecksumValidator validator = newValidator( SHA1, MD5 );
+ HashMap<String, String> provided = new HashMap<>();
+ provided.put( SHA1, "foo" );
+ ChecksumValidator validator = newValidator( provided, SHA1, MD5 );
fetcher.mock( SHA1, "foo" );
fetcher.mock( MD5, "bar" );
validator.validate( checksums( SHA1, "foo", MD5, "bar" ), checksums( SHA1, "foo", MD5, "bar" ) );
fetcher.assertFetchedFiles( SHA1, MD5 );
- policy.assertCallbacks( "match(SHA-1, 0001)", "match(MD5, 0001)", "match(SHA-1, 0000)", "match(MD5, 0000)",
- "noMore()" );
+ policy.assertCallbacks( "match(SHA-1, PROVIDED)", "match(SHA-1, REMOTE_INCLUDED)", "match(MD5, REMOTE_INCLUDED)",
+ "match(SHA-1, REMOTE_EXTERNAL)", "match(MD5, REMOTE_EXTERNAL)", "noMore()" );
}
@Test
@@ -331,7 +338,7 @@ public class ChecksumValidatorTest
ChecksumValidator validator = newValidator( SHA1 );
fetcher.mock( SHA1, "FOO" );
validator.validate( checksums( SHA1, "foo" ), checksums( SHA1, "foo" ) );
- policy.assertCallbacks( "match(SHA-1, 0001)", "match(SHA-1, 0000)", "noMore()" );
+ policy.assertCallbacks( "match(SHA-1, REMOTE_INCLUDED)", "match(SHA-1, REMOTE_EXTERNAL)", "noMore()" );
}
@Test
@@ -342,7 +349,7 @@ public class ChecksumValidatorTest
fetcher.mock( MD5, "bar" );
validator.validate( checksums( MD5, "bar" ), null );
fetcher.assertFetchedFiles( SHA1, MD5 );
- policy.assertCallbacks( "match(MD5, 0000)" );
+ policy.assertCallbacks( "match(MD5, REMOTE_EXTERNAL)" );
}
@Test
@@ -354,7 +361,7 @@ public class ChecksumValidatorTest
fetcher.mock( MD5, "bar" );
validator.validate( checksums( MD5, "bar" ), null );
fetcher.assertFetchedFiles( SHA1, MD5 );
- policy.assertCallbacks( "error(SHA-1, 0000, inaccessible)", "match(MD5, 0000)" );
+ policy.assertCallbacks( "error(SHA-1, REMOTE_EXTERNAL, inaccessible)", "match(MD5, REMOTE_EXTERNAL)" );
}
@Test
@@ -366,7 +373,7 @@ public class ChecksumValidatorTest
fetcher.mock( MD5, "bar" );
validator.validate( checksums( SHA1, null, MD5, "bar" ), null );
fetcher.assertFetchedFiles( MD5 );
- policy.assertCallbacks( "error(SHA-1, 0000, error)", "match(MD5, 0000)" );
+ policy.assertCallbacks( "error(SHA-1, REMOTE_EXTERNAL, error)", "match(MD5, REMOTE_EXTERNAL)" );
}
@Test
diff --git a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java
index 8ebddaa..6a88470 100644
--- a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java
+++ b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java
@@ -51,7 +51,7 @@ public class TestChecksumAlgorithmSelector
public static final String TEST_CHECKSUM_VALUE = "01020304";
@Override
- public Set<String> getChecksumAlgorithmNames()
+ public Set<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories()
{
return Collections.emptySet(); // irrelevant
}
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 c324fa9..9629dc9 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.FileProvidedChecksumsSource;
import org.eclipse.aether.internal.impl.TrackingFileManager;
import org.eclipse.aether.internal.impl.checksum.Md5ChecksumAlgorithmFactory;
import org.eclipse.aether.internal.impl.checksum.Sha1ChecksumAlgorithmFactory;
@@ -83,6 +84,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.checksum.ProvidedChecksumsSource;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
@@ -168,6 +170,9 @@ public class AetherModule
.to( EnhancedLocalRepositoryManagerFactory.class ).in( Singleton.class );
bind( TrackingFileManager.class ).to( DefaultTrackingFileManager.class ).in( Singleton.class );
+ bind( ProvidedChecksumsSource.class ).annotatedWith( Names.named( FileProvidedChecksumsSource.NAME ) ) //
+ .to( FileProvidedChecksumsSource.class ).in( Singleton.class );
+
bind( ChecksumAlgorithmFactory.class ).annotatedWith( Names.named( Md5ChecksumAlgorithmFactory.NAME ) )
.to( Md5ChecksumAlgorithmFactory.class );
bind( ChecksumAlgorithmFactory.class ).annotatedWith( Names.named( Sha1ChecksumAlgorithmFactory.NAME ) )
@@ -209,6 +214,17 @@ public class AetherModule
@Provides
@Singleton
+ Map<String, ProvidedChecksumsSource> provideChecksumSources(
+ @Named( FileProvidedChecksumsSource.NAME ) ProvidedChecksumsSource fileProvidedChecksumSource
+ )
+ {
+ Map<String, ProvidedChecksumsSource> providedChecksumsSource = new HashMap<>();
+ providedChecksumsSource.put( FileProvidedChecksumsSource.NAME, fileProvidedChecksumSource );
+ return providedChecksumsSource;
+ }
+
+ @Provides
+ @Singleton
Map<String, ChecksumAlgorithmFactory> provideChecksumTypes(
@Named( Sha512ChecksumAlgorithmFactory.NAME ) ChecksumAlgorithmFactory sha512,
@Named( Sha256ChecksumAlgorithmFactory.NAME ) ChecksumAlgorithmFactory sha256,
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java
index d5e1ecb..edb00f7 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java
@@ -41,26 +41,26 @@ abstract class AbstractChecksumPolicy
}
@Override
- public boolean onChecksumMatch( String algorithm, int kind )
+ public boolean onChecksumMatch( String algorithm, ChecksumKind kind )
{
requireNonNull( algorithm, "algorithm cannot be null" );
return true;
}
@Override
- public void onChecksumMismatch( String algorithm, int kind, ChecksumFailureException exception )
+ public void onChecksumMismatch( String algorithm, ChecksumKind kind, ChecksumFailureException exception )
throws ChecksumFailureException
{
requireNonNull( algorithm, "algorithm cannot be null" );
requireNonNull( exception, "exception cannot be null" );
- if ( ( kind & KIND_UNOFFICIAL ) == 0 )
+ if ( !kind.isIgnoreOnMismatch() )
{
throw exception;
}
}
@Override
- public void onChecksumError( String algorithm, int kind, ChecksumFailureException exception )
+ public void onChecksumError( String algorithm, ChecksumKind kind, ChecksumFailureException exception )
throws ChecksumFailureException
{
requireNonNull( algorithm, "algorithm cannot be null" );
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FileProvidedChecksumsSource.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FileProvidedChecksumsSource.java
new file mode 100644
index 0000000..2289fa5
--- /dev/null
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FileProvidedChecksumsSource.java
@@ -0,0 +1,169 @@
+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 org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.spi.connector.ArtifactDownload;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
+import org.eclipse.aether.spi.connector.checksum.ProvidedChecksumsSource;
+import org.eclipse.aether.spi.io.FileProcessor;
+import org.eclipse.aether.util.ConfigUtils;
+import org.eclipse.aether.util.artifact.ArtifactIdUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Local filesystem backed {@link ProvidedChecksumsSource} implementation that use specified directory as base
+ * directory, where it expects artifacts checksums on standard Maven2 "local" layout. This implementation uses Artifact
+ * (and Metadata) coordinates solely to form path from baseDir (for Metadata file name is
+ * {@code maven-metadata-local.xml.sha1} in case of SHA-1 checksum).
+ *
+ * @since 1.8.0
+ */
+@Singleton
+@Named( FileProvidedChecksumsSource.NAME )
+public final class FileProvidedChecksumsSource
+ implements ProvidedChecksumsSource
+{
+ public static final String NAME = "file";
+
+ static final String CONFIG_PROP_BASE_DIR = "aether.artifactResolver.providedChecksumsSource.file.baseDir";
+
+ static final String LOCAL_REPO_PREFIX = ".checksums";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger( FileProvidedChecksumsSource.class );
+
+ private final FileProcessor fileProcessor;
+
+ private final SimpleLocalRepositoryManager simpleLocalRepositoryManager;
+
+ @Inject
+ public FileProvidedChecksumsSource( FileProcessor fileProcessor )
+ {
+ this.fileProcessor = requireNonNull( fileProcessor );
+ // we really needs just "local layout" from it (relative paths), so baseDir here is irrelevant
+ this.simpleLocalRepositoryManager = new SimpleLocalRepositoryManager( new File( "" ) );
+ }
+
+ @Override
+ public Map<String, String> getProvidedArtifactChecksums( RepositorySystemSession session,
+ ArtifactDownload transfer,
+ List<ChecksumAlgorithmFactory> checksumAlgorithmFactories )
+ {
+ Path baseDir = getBaseDir( session );
+ if ( baseDir == null )
+ {
+ return null;
+ }
+ ArrayList<ChecksumFilePath> checksumFilePaths = new ArrayList<>( checksumAlgorithmFactories.size() );
+ for ( ChecksumAlgorithmFactory checksumAlgorithmFactory : checksumAlgorithmFactories )
+ {
+ checksumFilePaths.add( new ChecksumFilePath(
+ simpleLocalRepositoryManager.getPathForArtifact( transfer.getArtifact(), false ) + '.'
+ + checksumAlgorithmFactory.getFileExtension(), checksumAlgorithmFactory ) );
+ }
+ return getProvidedChecksums( baseDir, checksumFilePaths, ArtifactIdUtils.toId( transfer.getArtifact() ) );
+ }
+
+ /**
+ * May return {@code null}.
+ */
+ private Map<String, String> getProvidedChecksums( Path baseDir,
+ List<ChecksumFilePath> checksumFilePaths,
+ String subjectId )
+ {
+ HashMap<String, String> checksums = new HashMap<>();
+ for ( ChecksumFilePath checksumFilePath : checksumFilePaths )
+ {
+ Path checksumPath = baseDir.resolve( checksumFilePath.path );
+ if ( Files.isReadable( checksumPath ) )
+ {
+ try
+ {
+ String checksum = fileProcessor.readChecksum( checksumPath.toFile() );
+ if ( checksum != null )
+ {
+ LOGGER.debug( "Resolved provided checksum '{}:{}' for '{}'",
+ checksumFilePath.checksumAlgorithmFactory.getName(), checksum, subjectId );
+
+ checksums.put( checksumFilePath.checksumAlgorithmFactory.getName(), checksum );
+ }
+ }
+ catch ( IOException e )
+ {
+ LOGGER.warn( "Could not read provided checksum for '{}' at path '{}'",
+ subjectId, checksumPath, e );
+ }
+ }
+ }
+ return checksums.isEmpty() ? null : checksums;
+ }
+
+ /**
+ * Returns the base {@link URI} of directory where checksums are laid out, may return {@code null}.
+ */
+ private Path getBaseDir( RepositorySystemSession session )
+ {
+ 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( LOCAL_REPO_PREFIX );
+ }
+ if ( !Files.isDirectory( baseDir ) )
+ {
+ return null;
+ }
+ return baseDir;
+ }
+
+ private static final class ChecksumFilePath
+ {
+ private final String path;
+
+ private final ChecksumAlgorithmFactory checksumAlgorithmFactory;
+
+ private ChecksumFilePath( String path, ChecksumAlgorithmFactory checksumAlgorithmFactory )
+ {
+ this.path = path;
+ this.checksumAlgorithmFactory = checksumAlgorithmFactory;
+ }
+ }
+}
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 3715196..d0b3de9 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
@@ -26,7 +26,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
-import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Named;
@@ -148,9 +147,9 @@ public final class Maven2RepositoryLayoutFactory
}
@Override
- public List<String> getChecksumAlgorithmNames()
+ public List<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories()
{
- return checksumAlgorithms.stream().map( ChecksumAlgorithmFactory::getName ).collect( Collectors.toList() );
+ return checksumAlgorithms;
}
@Override
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector.java
index 3e6d657..d463100 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector.java
@@ -23,15 +23,16 @@ import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
+import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
+import java.util.List;
import java.util.Map;
-import java.util.Set;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
import static java.util.Objects.requireNonNull;
+import static java.util.stream.Collectors.toList;
/**
* Default implementation.
@@ -73,15 +74,19 @@ public class DefaultChecksumAlgorithmFactorySelector
{
throw new IllegalArgumentException(
String.format( "Unsupported checksum algorithm %s, supported ones are %s",
- algorithmName, getChecksumAlgorithmNames() )
+ algorithmName,
+ getChecksumAlgorithmFactories().stream()
+ .map( ChecksumAlgorithmFactory::getName )
+ .collect( toList() )
+ )
);
}
return factory;
}
@Override
- public Set<String> getChecksumAlgorithmNames()
+ public List<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories()
{
- return new HashSet<>( factories.keySet() );
+ return new ArrayList<>( factories.values() );
}
}
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..65ad488 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
@@ -38,8 +38,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;
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/FailChecksumPolicyTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/FailChecksumPolicyTest.java
index 9eceb40..512aa18 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/FailChecksumPolicyTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/FailChecksumPolicyTest.java
@@ -21,7 +21,7 @@ package org.eclipse.aether.internal.impl;
import static org.junit.Assert.*;
-import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy;
+import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy.ChecksumKind;
import org.eclipse.aether.transfer.ChecksumFailureException;
import org.eclipse.aether.transfer.TransferResource;
import org.junit.Before;
@@ -50,8 +50,9 @@ public class FailChecksumPolicyTest
@Test
public void testOnChecksumMatch()
{
- assertTrue( policy.onChecksumMatch( "SHA-1", 0 ) );
- assertTrue( policy.onChecksumMatch( "SHA-1", ChecksumPolicy.KIND_UNOFFICIAL ) );
+ assertTrue( policy.onChecksumMatch( "SHA-1", ChecksumKind.REMOTE_EXTERNAL ) );
+ assertTrue( policy.onChecksumMatch( "SHA-1", ChecksumKind.REMOTE_INCLUDED ) );
+ assertTrue( policy.onChecksumMatch( "SHA-1", ChecksumKind.PROVIDED ) );
}
@Test
@@ -60,21 +61,29 @@ public class FailChecksumPolicyTest
{
try
{
- policy.onChecksumMismatch( "SHA-1", 0, exception );
+ policy.onChecksumMismatch( "SHA-1", ChecksumKind.REMOTE_EXTERNAL, exception );
fail( "No exception" );
}
catch ( ChecksumFailureException e )
{
assertSame( exception, e );
}
- policy.onChecksumMismatch( "SHA-1", ChecksumPolicy.KIND_UNOFFICIAL, exception );
+ policy.onChecksumMismatch( "SHA-1", ChecksumKind.REMOTE_INCLUDED, exception );
+ try
+ {
+ policy.onChecksumMismatch("SHA-1", ChecksumKind.PROVIDED, exception);
+ }
+ catch ( ChecksumFailureException e)
+ {
+ assertSame( exception, e );
+ }
}
@Test
public void testOnChecksumError()
throws Exception
{
- policy.onChecksumError( "SHA-1", 0, exception );
+ policy.onChecksumError( "SHA-1", ChecksumKind.REMOTE_EXTERNAL, exception );
}
@Test
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/FileProvidedChecksumsSourceTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/FileProvidedChecksumsSourceTest.java
new file mode 100644
index 0000000..e062a32
--- /dev/null
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/FileProvidedChecksumsSourceTest.java
@@ -0,0 +1,107 @@
+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.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Map;
+
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.internal.impl.checksum.Sha1ChecksumAlgorithmFactory;
+import org.eclipse.aether.internal.test.util.TestFileProcessor;
+import org.eclipse.aether.internal.test.util.TestUtils;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.repository.RepositoryPolicy;
+import org.eclipse.aether.spi.connector.ArtifactDownload;
+import org.eclipse.aether.spi.connector.layout.RepositoryLayout;
+import org.eclipse.aether.transfer.NoRepositoryLayoutException;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class FileProvidedChecksumsSourceTest
+{
+ private DefaultRepositorySystemSession session;
+
+ private RepositoryLayout repositoryLayout;
+
+ private FileProvidedChecksumsSource subject;
+
+ @Before
+ public void setup() throws NoRepositoryLayoutException, IOException
+ {
+ RemoteRepository repository = new RemoteRepository.Builder("test", "default", "https://irrelevant.com").build();
+ session = TestUtils.newSession();
+ repositoryLayout = new Maven2RepositoryLayoutFactory().newInstance(session, repository);
+ subject = new FileProvidedChecksumsSource(new TestFileProcessor() );
+
+ // populate local repository
+ Path baseDir = session.getLocalRepository().getBasedir().toPath().resolve( FileProvidedChecksumsSource.LOCAL_REPO_PREFIX);
+
+ // artifact: test:test:2.0 => "foobar"
+ {
+ Path test = baseDir.resolve("test/test/2.0/test-2.0.jar.sha1");
+ Files.createDirectories(test.getParent());
+ Files.write(test, "foobar".getBytes(StandardCharsets.UTF_8));
+ }
+ }
+
+ @Test
+ public void noProvidedArtifactChecksum()
+ {
+ ArtifactDownload transfer = new ArtifactDownload(
+ new DefaultArtifact("test:test:1.0"),
+ "irrelevant",
+ new File("irrelevant"),
+ RepositoryPolicy.CHECKSUM_POLICY_FAIL
+ );
+ Map<String, String> providedChecksums = subject.getProvidedArtifactChecksums(
+ session,
+ transfer,
+ repositoryLayout.getChecksumAlgorithmFactories()
+ );
+ assertNull(providedChecksums);
+ }
+
+ @Test
+ public void haveProvidedArtifactChecksum()
+ {
+ ArtifactDownload transfer = new ArtifactDownload(
+ new DefaultArtifact("test:test:2.0"),
+ "irrelevant",
+ new File("irrelevant"),
+ RepositoryPolicy.CHECKSUM_POLICY_FAIL
+ );
+ Map<String, String> providedChecksums = subject.getProvidedArtifactChecksums(
+ session,
+ transfer,
+ repositoryLayout.getChecksumAlgorithmFactories()
+ );
+ assertNotNull(providedChecksums);
+ assertEquals(providedChecksums.get(Sha1ChecksumAlgorithmFactory.NAME), "foobar");
+ }
+}
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactoryTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactoryTest.java
index 311607c..108bf90 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactoryTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactoryTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.*;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.artifact.DefaultArtifact;
@@ -121,7 +122,11 @@ public class Maven2RepositoryLayoutFactoryTest
@Test
public void testChecksumAlgorithmNames()
{
- assertEquals( Arrays.asList( "SHA-1", "MD5" ), layout.getChecksumAlgorithmNames() );
+ assertEquals( Arrays.asList( "SHA-1", "MD5" ),
+ layout.getChecksumAlgorithmFactories().stream()
+ .map( ChecksumAlgorithmFactory::getName )
+ .collect( Collectors.toList() )
+ );
}
@Test
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/WarnChecksumPolicyTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/WarnChecksumPolicyTest.java
index 0f7b522..dd376a1 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/WarnChecksumPolicyTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/WarnChecksumPolicyTest.java
@@ -21,7 +21,7 @@ package org.eclipse.aether.internal.impl;
import static org.junit.Assert.*;
-import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy;
+import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy.ChecksumKind;
import org.eclipse.aether.transfer.ChecksumFailureException;
import org.eclipse.aether.transfer.TransferResource;
import org.junit.Before;
@@ -50,8 +50,8 @@ public class WarnChecksumPolicyTest
@Test
public void testOnChecksumMatch()
{
- assertTrue( policy.onChecksumMatch( "SHA-1", 0 ) );
- assertTrue( policy.onChecksumMatch( "SHA-1", ChecksumPolicy.KIND_UNOFFICIAL ) );
+ assertTrue( policy.onChecksumMatch( "SHA-1", ChecksumKind.REMOTE_EXTERNAL ) );
+ assertTrue( policy.onChecksumMatch( "SHA-1", ChecksumKind.REMOTE_INCLUDED ) );
}
@Test
@@ -60,21 +60,21 @@ public class WarnChecksumPolicyTest
{
try
{
- policy.onChecksumMismatch( "SHA-1", 0, exception );
+ policy.onChecksumMismatch( "SHA-1", ChecksumKind.REMOTE_EXTERNAL, exception );
fail( "No exception" );
}
catch ( ChecksumFailureException e )
{
assertSame( exception, e );
}
- policy.onChecksumMismatch( "SHA-1", ChecksumPolicy.KIND_UNOFFICIAL, exception );
+ policy.onChecksumMismatch( "SHA-1", ChecksumKind.REMOTE_INCLUDED, exception );
}
@Test
public void testOnChecksumError()
throws Exception
{
- policy.onChecksumError( "SHA-1", 0, exception );
+ policy.onChecksumError( "SHA-1", ChecksumKind.REMOTE_EXTERNAL, exception );
}
@Test
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector.java
index eece32e..5bc0aa2 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector.java
@@ -19,7 +19,7 @@ package org.eclipse.aether.spi.connector.checksum;
* under the License.
*/
-import java.util.Set;
+import java.util.Collection;
/**
* Component performing selection of {@link ChecksumAlgorithmFactory} based on known factory names.
@@ -36,9 +36,10 @@ public interface ChecksumAlgorithmFactorySelector
ChecksumAlgorithmFactory select( String algorithmName );
/**
- * Returns a set of supported algorithm names. This set represents ALL the algorithms supported by Resolver, and is
- * NOT in any relation to given repository layout used checksums, returned by method {@link
- * org.eclipse.aether.spi.connector.layout.RepositoryLayout#getChecksumAlgorithmNames()} (is super set of it).
+ * Returns a collection of supported algorithm names. This set represents ALL the algorithms supported by Resolver,
+ * and is NOT in any relation to given repository layout used checksums, returned by method {@link
+ * org.eclipse.aether.spi.connector.layout.RepositoryLayout#getChecksumAlgorithmFactories()} (in fact, is super set
+ * of it).
*/
- Set<String> getChecksumAlgorithmNames();
+ Collection<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories();
}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumPolicy.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumPolicy.java
index f7d7a37..2b6e04a 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumPolicy.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumPolicy.java
@@ -64,23 +64,57 @@ import org.eclipse.aether.transfer.ChecksumFailureException;
*/
public interface ChecksumPolicy
{
-
/**
- * Bit flag indicating a checksum which is not part of the official repository layout/structure.
+ * Enum denoting origin of checksum.
+ *
+ * @since 1.8.0
*/
- int KIND_UNOFFICIAL = 0x01;
+ enum ChecksumKind
+ {
+ /**
+ * Remote external kind of checksum are retrieved from remote doing extra transport round-trip (usually by
+ * getting "file.jar.sha1" for corresponding "file.jar" file). This kind of checksum is part of layout, and
+ * was from beginning the "official" (and one and only) checksum used by resolver.
+ */
+ REMOTE_EXTERNAL( false ),
+
+ /**
+ * Included checksums may be received from remote repository during the retrieval of the main file, for example
+ * from response headers in case of HTTP transport. They may be set with
+ * {@link org.eclipse.aether.spi.connector.transport.GetTask#setChecksum(String, String)}. Included checksums
+ * on mismatch are ignored, so {@link #REMOTE_EXTERNAL} will be trialed on mismatch.
+ */
+ REMOTE_INCLUDED( true ),
+
+ /**
+ * Provided checksums may be provided by {@link ProvidedChecksumsSource} components, ahead of artifact
+ * retrieval.
+ */
+ PROVIDED( false );
+
+ private final boolean ignoreOnMismatch;
+
+ ChecksumKind( boolean ignoreOnMismatch )
+ {
+ this.ignoreOnMismatch = ignoreOnMismatch;
+ }
+
+ public boolean isIgnoreOnMismatch()
+ {
+ return ignoreOnMismatch;
+ }
+ }
/**
* Signals a match between the locally computed checksum value and the checksum value declared by the remote
* repository.
*
* @param algorithm The name of the checksum algorithm being used, must not be {@code null}.
- * @param kind A bit field providing further details about the checksum. See the {@code KIND_*} constants in
- * this interface for possible bit flags.
+ * @param kind A field providing further details about the checksum.
* @return {@code true} to accept the download as valid and stop further validation, {@code false} to continue
* validation with the next checksum.
*/
- boolean onChecksumMatch( String algorithm, int kind );
+ boolean onChecksumMatch( String algorithm, ChecksumKind kind );
/**
* Signals a mismatch between the locally computed checksum value and the checksum value declared by the remote
@@ -88,14 +122,12 @@ public interface ChecksumPolicy
* their internal state and defer a conclusion until all available checksums have been processed.
*
* @param algorithm The name of the checksum algorithm being used, must not be {@code null}.
- * @param kind A bit field providing further details about the checksum. See the {@code KIND_*} constants in
- * this
- * interface for possible bit flags.
+ * @param kind A field providing further details about the checksum.
* @param exception The exception describing the checksum mismatch, must not be {@code null}.
* @throws ChecksumFailureException If the checksum validation is to be failed. If the method returns normally,
* validation continues with the next checksum.
*/
- void onChecksumMismatch( String algorithm, int kind, ChecksumFailureException exception )
+ void onChecksumMismatch( String algorithm, ChecksumKind kind, ChecksumFailureException exception )
throws ChecksumFailureException;
/**
@@ -103,14 +135,12 @@ public interface ChecksumPolicy
* repository.
*
* @param algorithm The name of the checksum algorithm being used, must not be {@code null}.
- * @param kind A bit field providing further details about the checksum. See the {@code KIND_*} constants in
- * this
- * interface for possible bit flags.
+ * @param kind A field providing further details about the checksum.
* @param exception The exception describing the checksum error, must not be {@code null}.
* @throws ChecksumFailureException If the checksum validation is to be failed. If the method returns normally,
* validation continues with the next checksum.
*/
- void onChecksumError( String algorithm, int kind, ChecksumFailureException exception )
+ void onChecksumError( String algorithm, ChecksumKind kind, ChecksumFailureException exception )
throws ChecksumFailureException;
/**
@@ -134,8 +164,8 @@ public interface ChecksumPolicy
* issue or insist on rejecting the downloaded file as unusable.
*
* @param exception The exception that was thrown from a prior call to
- * {@link #onChecksumMismatch(String, int, ChecksumFailureException)},
- * {@link #onChecksumError(String, int, ChecksumFailureException)} or {@link
+ * {@link #onChecksumMismatch(String, ChecksumKind, ChecksumFailureException)},
+ * {@link #onChecksumError(String, ChecksumKind, ChecksumFailureException)} or {@link
* #onNoMoreChecksums()}.
* @return {@code true} to accept the download nevertheless and let artifact resolution succeed, {@code false} to
* reject the transferred file as unusable.
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ProvidedChecksumsSource.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ProvidedChecksumsSource.java
new file mode 100644
index 0000000..b1d70b0
--- /dev/null
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ProvidedChecksumsSource.java
@@ -0,0 +1,47 @@
+package org.eclipse.aether.spi.connector.checksum;
+
+/*
+ * 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.List;
+import java.util.Map;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.spi.connector.ArtifactDownload;
+
+/**
+ * Component able to provide (expected) checksums beforehand the download happens. Checksum provided by this component
+ * are of kind {@link org.eclipse.aether.spi.connector.checksum.ChecksumPolicy.ChecksumKind#PROVIDED}.
+ *
+ * @since 1.8.0
+ */
+public interface ProvidedChecksumsSource
+{
+ /**
+ * May return the provided checksums (for given artifact transfer) from trusted source other than remote
+ * repository, or {@code null}.
+ *
+ * @param transfer The transfer that is about to be executed.
+ * @param checksumAlgorithmFactories The checksum algorithms that are expected.
+ * @return Map of expected checksums, or {@code null}.
+ */
+ Map<String, String> getProvidedArtifactChecksums( RepositorySystemSession session,
+ ArtifactDownload transfer,
+ List<ChecksumAlgorithmFactory> checksumAlgorithmFactories );
+}
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 8bc88a7..4a02b06 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
@@ -126,12 +126,12 @@ public interface RepositoryLayout
}
/**
- * Returns the list of checksum names this instance of layout uses, never {@code null}. The checksum order
- * represents the order how checksums are validated (hence retrieved).
+ * Returns immutable list of {@link ChecksumAlgorithmFactory} this instance of layout uses, never {@code null}.
+ * The order represents the order how checksums are validated (hence retrieved).
*
* @since 1.8.0
*/
- List<String> getChecksumAlgorithmNames();
+ List<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories();
/**
* Gets the location within a remote repository where the specified artifact resides. The URI is relative to the
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/transport/GetTask.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/transport/GetTask.java
index 3d30694..e6eb9a4 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/transport/GetTask.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/transport/GetTask.java
@@ -209,9 +209,10 @@ public final class GetTask
/**
* Gets the checksums which the remote repository advertises for the resource. The map is keyed by algorithm name
- * (cf. {@link java.security.MessageDigest#getInstance(String)}) and the values are hexadecimal representations of
- * the corresponding value. <em>Note:</em> This is optional data that a transporter may return if the underlying
- * transport protocol provides metadata (e.g. HTTP headers) along with the actual resource data.
+ * and the values are hexadecimal representations of the corresponding value. <em>Note:</em> This is optional
+ * data that a transporter may return if the underlying transport protocol provides metadata (e.g. HTTP headers)
+ * along with the actual resource data. Checksums returned by this method have kind of
+ * {@link org.eclipse.aether.spi.connector.checksum.ChecksumPolicy.ChecksumKind#REMOTE_INCLUDED}.
*
* @return The (read-only) checksums advertised for the downloaded resource, possibly empty but never {@code null}.
*/
@@ -225,8 +226,7 @@ public final class GetTask
* use this method to record checksum information which is readily available while performing the actual download,
* they should not perform additional transfers to gather this data.
*
- * @param algorithm The name of the checksum algorithm (e.g. {@code "SHA-1"}, cf.
- * {@link java.security.MessageDigest#getInstance(String)} ), may be {@code null}.
+ * @param algorithm The name of the checksum algorithm (e.g. {@code "SHA-1"}, may be {@code null}.
* @param value The hexadecimal representation of the checksum, may be {@code null}.
* @return This task for chaining, never {@code null}.
*/