You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2022/01/27 20:43:17 UTC
[maven-resolver] branch master updated: [MRESOLVER-230] Make supported checksum algorithms extensible
This is an automated email from the ASF dual-hosted git repository.
michaelo 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 375a290 [MRESOLVER-230] Make supported checksum algorithms extensible
375a290 is described below
commit 375a2909b86248cc6c1ebf747149ac123df16b9f
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Tue Dec 14 15:25:09 2021 +0100
[MRESOLVER-230] Make supported checksum algorithms extensible
This closes #139
---
.../connector/basic/BasicRepositoryConnector.java | 157 ++++++++++++---------
.../aether/connector/basic/ChecksumCalculator.java | 102 +++++--------
.../aether/connector/basic/ChecksumValidator.java | 67 +++++----
.../connector/basic/ChecksumCalculatorTest.java | 33 ++---
.../connector/basic/ChecksumValidatorTest.java | 39 ++---
.../basic/TestChecksumAlgorithmSelector.java | 124 ++++++++++++++++
.../eclipse/aether/impl/DefaultServiceLocator.java | 3 +
.../eclipse/aether/impl/guice/AetherModule.java | 106 +++++++++-----
.../internal/impl/AbstractChecksumPolicy.java | 17 ++-
.../aether/internal/impl/DefaultFileProcessor.java | 28 ++--
.../aether/internal/impl/FailChecksumPolicy.java | 1 +
.../impl/Maven2RepositoryLayoutFactory.java | 89 +++++++++---
.../aether/internal/impl/WarnChecksumPolicy.java | 1 +
.../DefaultChecksumAlgorithmFactorySelector.java | 87 ++++++++++++
.../Md5ChecksumAlgorithmFactory.java} | 33 ++---
...ssageDigestChecksumAlgorithmFactorySupport.java | 71 ++++++++++
.../Sha1ChecksumAlgorithmFactory.java} | 33 ++---
.../Sha256ChecksumAlgorithmFactory.java} | 33 ++---
.../Sha512ChecksumAlgorithmFactory.java} | 33 ++---
.../impl/Maven2RepositoryLayoutFactoryTest.java | 114 ++++++++++-----
.../spi/connector/checksum/ChecksumAlgorithm.java | 46 ++++++
.../checksum/ChecksumAlgorithmFactory.java | 48 +++++++
.../checksum/ChecksumAlgorithmFactorySelector.java | 44 ++++++
.../checksum/ChecksumAlgorithmFactorySupport.java | 59 ++++++++
.../checksum/ChecksumAlgorithmHelper.java | 103 ++++++++++++++
.../spi/connector/checksum/ChecksumPolicy.java | 55 ++++----
.../spi/connector/layout/RepositoryLayout.java | 118 ++++++++--------
.../connector/transport/AbstractTransporter.java | 12 +-
.../org/eclipse/aether/spi/io/FileProcessor.java | 16 +++
.../spi/connector/layout/ChecksumLocationTest.java | 95 +++++++++++++
.../aether/spi/connector/layout/ChecksumTest.java | 65 ---------
.../internal/test/util/TestFileProcessor.java | 12 ++
.../org/eclipse/aether/util/ChecksumUtils.java | 10 +-
src/site/markdown/about-checksums.md | 73 ++++++++++
src/site/markdown/configuration.md | 2 +-
src/site/site.xml | 1 +
36 files changed, 1397 insertions(+), 533 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..a338c6d 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
@@ -26,12 +26,11 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
@@ -47,6 +46,8 @@ 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.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.layout.RepositoryLayout;
@@ -64,7 +65,6 @@ import org.eclipse.aether.transfer.NoTransporterException;
import org.eclipse.aether.transfer.TransferEvent;
import org.eclipse.aether.transfer.TransferResource;
import org.eclipse.aether.transform.FileTransformer;
-import org.eclipse.aether.util.ChecksumUtils;
import org.eclipse.aether.util.ConfigUtils;
import org.eclipse.aether.util.concurrency.RunnableErrorForwarder;
import org.eclipse.aether.util.concurrency.WorkerThreadFactory;
@@ -72,9 +72,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
+ *
*/
final class BasicRepositoryConnector
- implements RepositoryConnector
+ implements RepositoryConnector
{
private static final String CONFIG_PROP_THREADS = "aether.connector.basic.threads";
@@ -111,10 +112,13 @@ final class BasicRepositoryConnector
private boolean closed;
- BasicRepositoryConnector( RepositorySystemSession session, RemoteRepository repository,
- TransporterProvider transporterProvider, RepositoryLayoutProvider layoutProvider,
- ChecksumPolicyProvider checksumPolicyProvider, FileProcessor fileProcessor )
- throws NoRepositoryConnectorException
+ BasicRepositoryConnector( RepositorySystemSession session,
+ RemoteRepository repository,
+ TransporterProvider transporterProvider,
+ RepositoryLayoutProvider layoutProvider,
+ ChecksumPolicyProvider checksumPolicyProvider,
+ FileProcessor fileProcessor )
+ throws NoRepositoryConnectorException
{
try
{
@@ -141,18 +145,19 @@ final class BasicRepositoryConnector
maxThreads = ConfigUtils.getInteger( session, 5, CONFIG_PROP_THREADS, "maven.artifact.threads" );
smartChecksums = ConfigUtils.getBoolean( session, true, CONFIG_PROP_SMART_CHECKSUMS );
persistedChecksums =
- ConfigUtils.getBoolean( session, ConfigurationProperties.DEFAULT_PERSISTED_CHECKSUMS,
- ConfigurationProperties.PERSISTED_CHECKSUMS );
+ ConfigUtils.getBoolean( session, ConfigurationProperties.DEFAULT_PERSISTED_CHECKSUMS,
+ ConfigurationProperties.PERSISTED_CHECKSUMS );
boolean resumeDownloads =
- ConfigUtils.getBoolean( session, true, CONFIG_PROP_RESUME + '.' + repository.getId(), CONFIG_PROP_RESUME );
+ ConfigUtils.getBoolean( session, true, CONFIG_PROP_RESUME + '.' + repository.getId(),
+ CONFIG_PROP_RESUME );
long resumeThreshold =
- ConfigUtils.getLong( session, 64 * 1024, CONFIG_PROP_RESUME_THRESHOLD + '.' + repository.getId(),
- CONFIG_PROP_RESUME_THRESHOLD );
+ ConfigUtils.getLong( session, 64 * 1024, CONFIG_PROP_RESUME_THRESHOLD + '.' + repository.getId(),
+ CONFIG_PROP_RESUME_THRESHOLD );
int requestTimeout =
- ConfigUtils.getInteger( session, ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT,
- ConfigurationProperties.REQUEST_TIMEOUT + '.' + repository.getId(),
- ConfigurationProperties.REQUEST_TIMEOUT );
+ ConfigUtils.getInteger( session, ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT,
+ ConfigurationProperties.REQUEST_TIMEOUT + '.' + repository.getId(),
+ ConfigurationProperties.REQUEST_TIMEOUT );
partialFileFactory = new PartialFile.Factory( resumeDownloads, resumeThreshold, requestTimeout );
}
@@ -170,17 +175,17 @@ final class BasicRepositoryConnector
if ( executor == null )
{
executor =
- new ThreadPoolExecutor( maxThreads, maxThreads, 3L, TimeUnit.SECONDS,
- new LinkedBlockingQueue<Runnable>(),
- new WorkerThreadFactory( getClass().getSimpleName() + '-'
- + repository.getHost() + '-' ) );
+ new ThreadPoolExecutor( maxThreads, maxThreads, 3L, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<>(),
+ new WorkerThreadFactory( getClass().getSimpleName() + '-'
+ + repository.getHost() + '-' ) );
}
return executor;
}
@Override
protected void finalize()
- throws Throwable
+ throws Throwable
{
try
{
@@ -192,6 +197,7 @@ final class BasicRepositoryConnector
}
}
+ @Override
public void close()
{
if ( !closed )
@@ -205,6 +211,7 @@ final class BasicRepositoryConnector
}
}
+ @Override
public void get( Collection<? extends ArtifactDownload> artifactDownloads,
Collection<? extends MetadataDownload> metadataDownloads )
{
@@ -225,13 +232,14 @@ final class BasicRepositoryConnector
MetadataTransportListener listener = new MetadataTransportListener( transfer, repository, builder );
ChecksumPolicy checksumPolicy = newChecksumPolicy( transfer.getChecksumPolicy(), resource );
- List<RepositoryLayout.Checksum> checksums = null;
+ List<RepositoryLayout.ChecksumLocation> checksumLocations = null;
if ( checksumPolicy != null )
{
- checksums = layout.getChecksums( transfer.getMetadata(), false, location );
+ checksumLocations = layout.getChecksumLocations( transfer.getMetadata(), false, location );
}
- Runnable task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy, checksums, listener );
+ Runnable task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy,
+ checksumLocations, listener );
executor.execute( errorForwarder.wrap( task ) );
}
@@ -251,13 +259,13 @@ final class BasicRepositoryConnector
else
{
ChecksumPolicy checksumPolicy = newChecksumPolicy( transfer.getChecksumPolicy(), resource );
- List<RepositoryLayout.Checksum> checksums = null;
+ List<RepositoryLayout.ChecksumLocation> checksumLocations = null;
if ( checksumPolicy != null )
{
- checksums = layout.getChecksums( transfer.getArtifact(), false, location );
+ checksumLocations = layout.getChecksumLocations( transfer.getArtifact(), false, location );
}
- task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy, checksums, listener );
+ task = new GetTaskRunner( location, transfer.getFile(), checksumPolicy, checksumLocations, listener );
}
executor.execute( errorForwarder.wrap( task ) );
}
@@ -265,6 +273,7 @@ final class BasicRepositoryConnector
errorForwarder.await();
}
+ @Override
public void put( Collection<? extends ArtifactUpload> artifactUploads,
Collection<? extends MetadataUpload> metadataUploads )
{
@@ -281,10 +290,11 @@ final class BasicRepositoryConnector
TransferEvent.Builder builder = newEventBuilder( resource, true, false );
ArtifactTransportListener listener = new ArtifactTransportListener( transfer, repository, builder );
- List<RepositoryLayout.Checksum> checksums = layout.getChecksums( transfer.getArtifact(), true, location );
+ List<RepositoryLayout.ChecksumLocation> checksumLocations =
+ layout.getChecksumLocations( transfer.getArtifact(), true, location );
- Runnable task = new PutTaskRunner( location, transfer.getFile(), transfer.getFileTransformer(), checksums,
- listener );
+ Runnable task = new PutTaskRunner( location, transfer.getFile(), transfer.getFileTransformer(),
+ checksumLocations, listener );
task.run();
}
@@ -296,16 +306,17 @@ final class BasicRepositoryConnector
TransferEvent.Builder builder = newEventBuilder( resource, true, false );
MetadataTransportListener listener = new MetadataTransportListener( transfer, repository, builder );
- List<RepositoryLayout.Checksum> checksums = layout.getChecksums( transfer.getMetadata(), true, location );
+ List<RepositoryLayout.ChecksumLocation> checksumLocations =
+ layout.getChecksumLocations( transfer.getMetadata(), true, location );
- Runnable task = new PutTaskRunner( location, transfer.getFile(), checksums, listener );
+ Runnable task = new PutTaskRunner( location, transfer.getFile(), checksumLocations, listener );
task.run();
}
}
private static <T> Collection<T> safe( Collection<T> items )
{
- return ( items != null ) ? items : Collections.<T>emptyList();
+ return ( items != null ) ? items : Collections.emptyList();
}
private TransferResource newTransferResource( URI path, File file, RequestTrace trace )
@@ -343,7 +354,7 @@ final class BasicRepositoryConnector
}
abstract class TaskRunner
- implements Runnable
+ implements Runnable
{
protected final URI path;
@@ -356,6 +367,7 @@ final class BasicRepositoryConnector
this.listener = listener;
}
+ @Override
public void run()
{
try
@@ -371,12 +383,12 @@ final class BasicRepositoryConnector
}
protected abstract void runTask()
- throws Exception;
+ throws Exception;
}
class PeekTaskRunner
- extends TaskRunner
+ extends TaskRunner
{
PeekTaskRunner( URI path, TransferTransportListener<?> listener )
@@ -384,8 +396,9 @@ final class BasicRepositoryConnector
super( path, listener );
}
+ @Override
protected void runTask()
- throws Exception
+ throws Exception
{
transporter.peek( new PeekTask( path ) );
}
@@ -393,8 +406,8 @@ final class BasicRepositoryConnector
}
class GetTaskRunner
- extends TaskRunner
- implements PartialFile.RemoteAccessChecker, ChecksumValidator.ChecksumFetcher
+ extends TaskRunner
+ implements PartialFile.RemoteAccessChecker, ChecksumValidator.ChecksumFetcher
{
private final File file;
@@ -402,22 +415,25 @@ final class BasicRepositoryConnector
private final ChecksumValidator checksumValidator;
GetTaskRunner( URI path, File file, ChecksumPolicy checksumPolicy,
- List<RepositoryLayout.Checksum> checksums, TransferTransportListener<?> listener )
+ List<RepositoryLayout.ChecksumLocation> checksumLocations,
+ TransferTransportListener<?> listener )
{
super( path, listener );
this.file = requireNonNull( file, "destination file cannot be null" );
- checksumValidator =
- new ChecksumValidator( file, fileProcessor, this, checksumPolicy, safe( checksums ) );
+ checksumValidator = new ChecksumValidator( file, fileProcessor, this,
+ checksumPolicy, safe( checksumLocations ) );
}
+ @Override
public void checkRemoteAccess()
- throws Exception
+ throws Exception
{
transporter.peek( new PeekTask( path ) );
}
+ @Override
public boolean fetchChecksum( URI remote, File local )
- throws Exception
+ throws Exception
{
try
{
@@ -434,8 +450,9 @@ final class BasicRepositoryConnector
return true;
}
+ @Override
protected void runTask()
- throws Exception
+ throws Exception
{
fileProcessor.mkdirs( file.getParentFile() );
@@ -450,7 +467,7 @@ final class BasicRepositoryConnector
{
File tmp = partFile.getFile();
listener.setChecksumCalculator( checksumValidator.newChecksumCalculator( tmp ) );
- for ( int firstTrial = 0, lastTrial = 1, trial = firstTrial;; trial++ )
+ for ( int firstTrial = 0, lastTrial = 1, trial = firstTrial; ; trial++ )
{
boolean resume = partFile.isResume() && trial <= firstTrial;
GetTask task = new GetTask( path ).setDataFile( tmp, resume ).setListener( listener );
@@ -458,7 +475,7 @@ final class BasicRepositoryConnector
try
{
checksumValidator.validate( listener.getChecksums(), smartChecksums ? task.getChecksums()
- : null );
+ : null );
break;
}
catch ( ChecksumFailureException e )
@@ -495,19 +512,19 @@ final class BasicRepositoryConnector
}
class PutTaskRunner
- extends TaskRunner
+ extends TaskRunner
{
private final File file;
private final FileTransformer fileTransformer;
- private final Collection<RepositoryLayout.Checksum> checksums;
+ private final Collection<RepositoryLayout.ChecksumLocation> checksumLocations;
- PutTaskRunner( URI path, File file, List<RepositoryLayout.Checksum> checksums,
+ PutTaskRunner( URI path, File file, List<RepositoryLayout.ChecksumLocation> checksumLocations,
TransferTransportListener<?> listener )
{
- this( path, file, null, checksums, listener );
+ this( path, file, null, checksumLocations, listener );
}
/**
@@ -517,21 +534,23 @@ final class BasicRepositoryConnector
* @param path
* @param file
* @param fileTransformer
- * @param checksums
+ * @param checksumLocations
* @param listener
*/
- PutTaskRunner( URI path, File file, FileTransformer fileTransformer, List<RepositoryLayout.Checksum> checksums,
- TransferTransportListener<?> listener )
+ PutTaskRunner( URI path, File file, FileTransformer fileTransformer,
+ List<RepositoryLayout.ChecksumLocation> checksumLocations,
+ TransferTransportListener<?> listener )
{
super( path, listener );
this.file = requireNonNull( file, "source file cannot be null" );
this.fileTransformer = fileTransformer;
- this.checksums = safe( checksums );
+ this.checksumLocations = safe( checksumLocations );
}
@SuppressWarnings( "checkstyle:innerassignment" )
+ @Override
protected void runTask()
- throws Exception
+ throws Exception
{
if ( fileTransformer != null )
{
@@ -559,37 +578,37 @@ final class BasicRepositoryConnector
}
/**
- *
- * @param file source
+ * @param file source
* @param bytes transformed data from file or {@code null}
*/
private void uploadChecksums( File file, byte[] bytes )
{
- if ( checksums.isEmpty() )
+ if ( checksumLocations.isEmpty() )
{
return;
}
try
{
- Set<String> algos = new HashSet<>();
- for ( RepositoryLayout.Checksum checksum : checksums )
+ ArrayList<ChecksumAlgorithmFactory> algorithms = new ArrayList<>();
+ for ( RepositoryLayout.ChecksumLocation checksumLocation : checksumLocations )
{
- algos.add( checksum.getAlgorithm() );
+ algorithms.add( checksumLocation.getChecksumAlgorithmFactory() );
}
- Map<String, Object> sumsByAlgo;
+ Map<String, String> sumsByAlgo;
if ( bytes != null )
{
- sumsByAlgo = ChecksumUtils.calc( bytes, algos );
+ sumsByAlgo = ChecksumAlgorithmHelper.calculate( bytes, algorithms );
}
else
{
- sumsByAlgo = ChecksumUtils.calc( file, algos );
+ sumsByAlgo = ChecksumAlgorithmHelper.calculate( file, algorithms );
}
- for ( RepositoryLayout.Checksum checksum : checksums )
+ for ( RepositoryLayout.ChecksumLocation checksumLocation : checksumLocations )
{
- uploadChecksum( checksum.getLocation(), sumsByAlgo.get( checksum.getAlgorithm() ) );
+ uploadChecksum( checksumLocation.getLocation(),
+ sumsByAlgo.get( checksumLocation.getChecksumAlgorithmFactory().getName() ) );
}
}
catch ( IOException e )
@@ -617,16 +636,16 @@ final class BasicRepositoryConnector
}
private static class DirectExecutor
- implements Executor
+ implements Executor
{
static final Executor INSTANCE = new DirectExecutor();
+ @Override
public void execute( Runnable command )
{
command.run();
}
}
-
}
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumCalculator.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumCalculator.java
index 0173fbb..87eeb78 100644
--- a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumCalculator.java
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumCalculator.java
@@ -19,14 +19,13 @@ package org.eclipse.aether.connector.basic;
* under the License.
*/
+import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -35,8 +34,11 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithm;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
import org.eclipse.aether.spi.connector.layout.RepositoryLayout;
-import org.eclipse.aether.util.ChecksumUtils;
+
+import static java.util.Objects.requireNonNull;
/**
* Calculates checksums for a downloaded file.
@@ -46,50 +48,32 @@ final class ChecksumCalculator
static class Checksum
{
- final String algorithm;
+ final ChecksumAlgorithmFactory checksumAlgorithmFactory;
- final MessageDigest digest;
+ ChecksumAlgorithm algorithm;
Exception error;
- Checksum( String algorithm )
+ Checksum( ChecksumAlgorithmFactory checksumAlgorithmFactory )
{
- this.algorithm = algorithm;
- MessageDigest digest = null;
- try
- {
- digest = MessageDigest.getInstance( algorithm );
- }
- catch ( NoSuchAlgorithmException e )
- {
- error = e;
- }
- this.digest = digest;
+ this.checksumAlgorithmFactory = requireNonNull( checksumAlgorithmFactory );
+ this.algorithm = checksumAlgorithmFactory.getAlgorithm();
}
- public void update( ByteBuffer buffer )
+ public void reset()
{
- if ( digest != null )
- {
- digest.update( buffer );
- }
+ this.algorithm = checksumAlgorithmFactory.getAlgorithm();
+ this.error = null;
}
- public void reset()
+ public void update( ByteBuffer buffer )
{
- if ( digest != null )
- {
- digest.reset();
- error = null;
- }
+ this.algorithm.update( buffer );
}
public void error( Exception error )
{
- if ( digest != null )
- {
- this.error = error;
- }
+ this.error = error;
}
public Object get()
@@ -98,7 +82,7 @@ final class ChecksumCalculator
{
return error;
}
- return ChecksumUtils.toHexString( digest.digest() );
+ return algorithm.checksum();
}
}
@@ -107,25 +91,26 @@ final class ChecksumCalculator
private final File targetFile;
- public static ChecksumCalculator newInstance( File targetFile, Collection<RepositoryLayout.Checksum> checksums )
+ public static ChecksumCalculator newInstance( File targetFile,
+ Collection<RepositoryLayout.ChecksumLocation> checksumLocations )
{
- if ( checksums == null || checksums.isEmpty() )
+ if ( checksumLocations == null || checksumLocations.isEmpty() )
{
return null;
}
- return new ChecksumCalculator( targetFile, checksums );
+ return new ChecksumCalculator( targetFile, checksumLocations );
}
- private ChecksumCalculator( File targetFile, Collection<RepositoryLayout.Checksum> checksums )
+ private ChecksumCalculator( File targetFile,
+ Collection<RepositoryLayout.ChecksumLocation> checksumLocations )
{
this.checksums = new ArrayList<>();
Set<String> algos = new HashSet<>();
- for ( RepositoryLayout.Checksum checksum : checksums )
+ for ( RepositoryLayout.ChecksumLocation checksumLocation : checksumLocations )
{
- String algo = checksum.getAlgorithm();
- if ( algos.add( algo ) )
+ if ( algos.add( checksumLocation.getChecksumAlgorithmFactory().getName() ) )
{
- this.checksums.add( new Checksum( algo ) );
+ this.checksums.add( new Checksum( checksumLocation.getChecksumAlgorithmFactory() ) );
}
}
this.targetFile = targetFile;
@@ -142,32 +127,25 @@ final class ChecksumCalculator
return;
}
- InputStream in = null;
- try
+ try ( InputStream in = new BufferedInputStream( new FileInputStream( targetFile ) ) )
{
- in = new FileInputStream( targetFile );
long total = 0;
- ByteBuffer buffer = ByteBuffer.allocate( 1024 * 32 );
- for ( byte[] array = buffer.array(); total < dataOffset; )
+ final byte[] buffer = new byte[ 1024 * 32 ];
+ for ( ; total < dataOffset; )
{
- int read = in.read( array );
+ int read = in.read( buffer );
if ( read < 0 )
{
throw new IOException( targetFile + " contains only " + total
- + " bytes, cannot resume download from offset " + dataOffset );
+ + " bytes, cannot resume download from offset " + dataOffset );
}
total += read;
if ( total > dataOffset )
{
read -= total - dataOffset;
}
- ( (Buffer) buffer ).rewind();
- ( (Buffer) buffer ).limit( read );
- update( buffer );
+ update( ByteBuffer.wrap( buffer, 0, read ) );
}
-
- in.close();
- in = null;
}
catch ( IOException e )
{
@@ -176,20 +154,6 @@ final class ChecksumCalculator
checksum.error( e );
}
}
- finally
- {
- try
- {
- if ( in != null )
- {
- in.close();
- }
- }
- catch ( IOException e )
- {
- // Suppressed due to an exception already thrown in the try block.
- }
- }
}
public void update( ByteBuffer data )
@@ -207,7 +171,7 @@ final class ChecksumCalculator
Map<String, Object> results = new HashMap<>();
for ( Checksum checksum : checksums )
{
- results.put( checksum.algorithm, checksum.get() );
+ results.put( checksum.checksumAlgorithmFactory.getName(), checksum.get() );
}
return results;
}
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..2e4e3b7 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
@@ -25,15 +25,14 @@ import java.net.URI;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Locale;
import java.util.Map;
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.layout.RepositoryLayout.Checksum;
+import org.eclipse.aether.spi.connector.layout.RepositoryLayout.ChecksumLocation;
import org.eclipse.aether.spi.io.FileProcessor;
import org.eclipse.aether.transfer.ChecksumFailureException;
-import org.eclipse.aether.util.ChecksumUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,28 +62,30 @@ final class ChecksumValidator
private final ChecksumPolicy checksumPolicy;
- private final Collection<Checksum> checksums;
+ private final Collection<ChecksumLocation> checksumLocations;
private final Map<File, Object> checksumFiles;
- ChecksumValidator( File dataFile, FileProcessor fileProcessor,
- ChecksumFetcher checksumFetcher, ChecksumPolicy checksumPolicy,
- Collection<Checksum> checksums )
+ ChecksumValidator( File dataFile,
+ FileProcessor fileProcessor,
+ ChecksumFetcher checksumFetcher,
+ ChecksumPolicy checksumPolicy,
+ Collection<ChecksumLocation> checksumLocations )
{
this.dataFile = dataFile;
this.tempFiles = new HashSet<>();
this.fileProcessor = fileProcessor;
this.checksumFetcher = checksumFetcher;
this.checksumPolicy = checksumPolicy;
- this.checksums = checksums;
- checksumFiles = new HashMap<>();
+ this.checksumLocations = checksumLocations;
+ this.checksumFiles = new HashMap<>();
}
public ChecksumCalculator newChecksumCalculator( File targetFile )
{
if ( checksumPolicy != null )
{
- return ChecksumCalculator.newInstance( targetFile, checksums );
+ return ChecksumCalculator.newInstance( targetFile, checksumLocations );
}
return null;
}
@@ -118,17 +119,26 @@ final class ChecksumValidator
{
continue;
}
+ ChecksumLocation checksumLocation = checksumLocations.stream()
+ .filter( a -> a.getChecksumAlgorithmFactory().getName().equals( algo ) )
+ .findFirst()
+ .orElse( null );
+ if ( checksumLocation == null )
+ {
+ continue;
+ }
String actual = String.valueOf( calculated );
String expected = entry.getValue().toString();
- checksumFiles.put( getChecksumFile( algo ), expected );
+ ChecksumAlgorithmFactory factory = checksumLocation.getChecksumAlgorithmFactory();
+ checksumFiles.put( getChecksumFile( factory ), expected );
if ( !isEqualChecksum( expected, actual ) )
{
- checksumPolicy.onChecksumMismatch( algo, ChecksumPolicy.KIND_UNOFFICIAL,
+ checksumPolicy.onChecksumMismatch( factory.getName(), ChecksumPolicy.KIND_UNOFFICIAL,
new ChecksumFailureException( expected, actual ) );
}
- else if ( checksumPolicy.onChecksumMatch( algo, ChecksumPolicy.KIND_UNOFFICIAL ) )
+ else if ( checksumPolicy.onChecksumMatch( factory.getName(), ChecksumPolicy.KIND_UNOFFICIAL ) )
{
return true;
}
@@ -139,48 +149,50 @@ final class ChecksumValidator
private boolean validateExternalChecksums( Map<String, ?> actualChecksums )
throws ChecksumFailureException
{
- for ( Checksum checksum : checksums )
+ for ( ChecksumLocation checksumLocation : checksumLocations )
{
- String algo = checksum.getAlgorithm();
- Object calculated = actualChecksums.get( algo );
+ ChecksumAlgorithmFactory factory = checksumLocation.getChecksumAlgorithmFactory();
+ Object calculated = actualChecksums.get( factory.getName() );
if ( calculated instanceof Exception )
{
- checksumPolicy.onChecksumError( algo, 0, new ChecksumFailureException( (Exception) calculated ) );
+ checksumPolicy.onChecksumError(
+ factory.getName(), 0, new ChecksumFailureException( (Exception) calculated ) );
continue;
}
try
{
- File checksumFile = getChecksumFile( checksum.getAlgorithm() );
+ File checksumFile = getChecksumFile( checksumLocation.getChecksumAlgorithmFactory() );
File tmp = createTempFile( checksumFile );
try
{
- if ( !checksumFetcher.fetchChecksum( checksum.getLocation(), tmp ) )
+ if ( !checksumFetcher.fetchChecksum( checksumLocation.getLocation(), tmp ) )
{
continue;
}
}
catch ( Exception e )
{
- checksumPolicy.onChecksumError( algo, 0, new ChecksumFailureException( e ) );
+ checksumPolicy.onChecksumError( factory.getName(), 0, new ChecksumFailureException( e ) );
continue;
}
String actual = String.valueOf( calculated );
- String expected = ChecksumUtils.read( tmp );
+ String expected = fileProcessor.readChecksum( tmp );
checksumFiles.put( checksumFile, tmp );
if ( !isEqualChecksum( expected, actual ) )
{
- checksumPolicy.onChecksumMismatch( algo, 0, new ChecksumFailureException( expected, actual ) );
+ checksumPolicy.onChecksumMismatch(
+ factory.getName(), 0, new ChecksumFailureException( expected, actual ) );
}
- else if ( checksumPolicy.onChecksumMatch( algo, 0 ) )
+ else if ( checksumPolicy.onChecksumMatch( factory.getName(), 0 ) )
{
return true;
}
}
catch ( IOException e )
{
- checksumPolicy.onChecksumError( algo, 0, new ChecksumFailureException( e ) );
+ checksumPolicy.onChecksumError( factory.getName(), 0, new ChecksumFailureException( e ) );
}
}
return false;
@@ -191,10 +203,9 @@ final class ChecksumValidator
return expected.equalsIgnoreCase( actual );
}
- private File getChecksumFile( String algorithm )
+ private File getChecksumFile( ChecksumAlgorithmFactory factory )
{
- String ext = algorithm.replace( "-", "" ).toLowerCase( Locale.ENGLISH );
- return new File( dataFile.getPath() + '.' + ext );
+ return new File( dataFile.getPath() + '.' + factory.getFileExtension() );
}
private File createTempFile( File path )
@@ -246,7 +257,7 @@ final class ChecksumValidator
}
else
{
- fileProcessor.write( checksumFile, String.valueOf( tmp ) );
+ fileProcessor.writeChecksum( checksumFile, String.valueOf( tmp ) );
}
}
catch ( IOException e )
diff --git a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumCalculatorTest.java b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumCalculatorTest.java
index a903386..818de7c 100644
--- a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumCalculatorTest.java
+++ b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/ChecksumCalculatorTest.java
@@ -19,6 +19,10 @@ package org.eclipse.aether.connector.basic;
* under the License.
*/
+import static org.eclipse.aether.connector.basic.TestChecksumAlgorithmSelector.MD5;
+import static org.eclipse.aether.connector.basic.TestChecksumAlgorithmSelector.SHA1;
+import static org.eclipse.aether.connector.basic.TestChecksumAlgorithmSelector.SHA256;
+import static org.eclipse.aether.connector.basic.TestChecksumAlgorithmSelector.SHA512;
import static org.junit.Assert.*;
import java.io.File;
@@ -26,7 +30,6 @@ import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
-import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -39,24 +42,18 @@ import org.junit.Test;
public class ChecksumCalculatorTest
{
- private static final String SHA512 = "SHA-512";
-
- private static final String SHA256 = "SHA-256";
-
- private static final String SHA1 = "SHA-1";
-
- private static final String MD5 = "MD5";
-
private File file;
+ private final TestChecksumAlgorithmSelector selector = new TestChecksumAlgorithmSelector();
+
private ChecksumCalculator newCalculator( String... algos )
{
- List<RepositoryLayout.Checksum> checksums = new ArrayList<>();
+ List<RepositoryLayout.ChecksumLocation> checksumLocations = new ArrayList<>();
for ( String algo : algos )
{
- checksums.add( new RepositoryLayout.Checksum( algo, URI.create( "irrelevant" ) ) );
+ checksumLocations.add( new RepositoryLayout.ChecksumLocation( URI.create( "irrelevant" ), selector.select( algo ) ) );
}
- return ChecksumCalculator.newInstance( file, checksums );
+ return ChecksumCalculator.newInstance( file, checksumLocations );
}
private ByteBuffer toBuffer( String data )
@@ -116,17 +113,11 @@ public class ChecksumCalculatorTest
assertEquals( 4, digests.size() );
}
- @Test
+ @Test( expected = IllegalArgumentException.class )
public void testUnknownAlgorithm()
{
- ChecksumCalculator calculator = newCalculator( "unknown", SHA1 );
- calculator.init( 0 );
- calculator.update( toBuffer( "Hello World!" ) );
- Map<String, Object> digests = calculator.get();
- assertNotNull( digests );
- assertEquals( "2ef7bde608ce5404e97d5f042f95f89f1c232871", digests.get( SHA1 ) );
- assertTrue( digests.get( "unknown" ) instanceof NoSuchAlgorithmException );
- assertEquals( 2, digests.size() );
+ // resolver now does not tolerate unknown checksums: as they may be set by user only, it is user misconfiguration
+ newCalculator( "unknown", SHA1 );
}
@Test
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..aac3c1b 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
@@ -19,6 +19,8 @@ package org.eclipse.aether.connector.basic;
* under the License.
*/
+import static org.eclipse.aether.connector.basic.TestChecksumAlgorithmSelector.MD5;
+import static org.eclipse.aether.connector.basic.TestChecksumAlgorithmSelector.SHA1;
import static org.junit.Assert.*;
import java.io.File;
@@ -50,10 +52,11 @@ public class ChecksumValidatorTest
boolean tolerateFailure;
- private List<String> callbacks = new ArrayList<>();
+ private final ArrayList<String> callbacks = new ArrayList<>();
private Object conclusion;
+ @Override
public boolean onChecksumMatch( String algorithm, int kind )
{
callbacks.add( String.format( "match(%s, %04x)", algorithm, kind ) );
@@ -68,6 +71,7 @@ public class ChecksumValidatorTest
return true;
}
+ @Override
public void onChecksumMismatch( String algorithm, int kind, ChecksumFailureException exception )
throws ChecksumFailureException
{
@@ -80,11 +84,13 @@ public class ChecksumValidatorTest
throw exception;
}
+ @Override
public void onChecksumError( String algorithm, int kind, ChecksumFailureException exception )
{
callbacks.add( String.format( "error(%s, %04x, %s)", algorithm, kind, exception.getCause().getMessage() ) );
}
+ @Override
public void onNoMoreChecksums()
throws ChecksumFailureException
{
@@ -99,11 +105,13 @@ public class ChecksumValidatorTest
}
}
+ @Override
public void onTransferRetry()
{
callbacks.add( String.format( "retry()" ) );
}
+ @Override
public boolean onTransferChecksumFailure( ChecksumFailureException exception )
{
callbacks.add( String.format( "fail(%s)", exception.getMessage() ) );
@@ -121,12 +129,13 @@ public class ChecksumValidatorTest
implements ChecksumValidator.ChecksumFetcher
{
- Map<URI, Object> checksums = new HashMap<>();
+ HashMap<URI, Object> checksums = new HashMap<>();
- List<File> checksumFiles = new ArrayList<>();
+ ArrayList<File> checksumFiles = new ArrayList<>();
- private List<URI> fetchedFiles = new ArrayList<>();
+ private final ArrayList<URI> fetchedFiles = new ArrayList<>();
+ @Override
public boolean fetchChecksum( URI remote, File local )
throws Exception
{
@@ -167,34 +176,32 @@ public class ChecksumValidatorTest
}
- private static final String SHA1 = "SHA-1";
-
- private static final String MD5 = "MD5";
-
private StubChecksumPolicy policy;
private StubChecksumFetcher fetcher;
private File dataFile;
- private static RepositoryLayout.Checksum newChecksum( String algo )
+ private static final TestChecksumAlgorithmSelector selector = new TestChecksumAlgorithmSelector();
+
+ private static RepositoryLayout.ChecksumLocation newChecksum( String factory )
{
- return RepositoryLayout.Checksum.forLocation( URI.create( "file" ), algo );
+ return RepositoryLayout.ChecksumLocation.forLocation( URI.create( "file" ), selector.select( factory ) );
}
- private List<RepositoryLayout.Checksum> newChecksums( String... algos )
+ private List<RepositoryLayout.ChecksumLocation> newChecksums( String... factories )
{
- List<RepositoryLayout.Checksum> checksums = new ArrayList<>();
- for ( String algo : algos )
+ List<RepositoryLayout.ChecksumLocation> checksums = new ArrayList<>();
+ for ( String factory : factories )
{
- checksums.add( newChecksum( algo ) );
+ checksums.add( newChecksum( factory ) );
}
return checksums;
}
- private ChecksumValidator newValidator( String... algos )
+ private ChecksumValidator newValidator( String... factories )
{
- return new ChecksumValidator( dataFile, new TestFileProcessor(), fetcher, policy, newChecksums( algos ) );
+ return new ChecksumValidator( dataFile, new TestFileProcessor(), fetcher, policy, newChecksums( factories ) );
}
private Map<String, ?> checksums( String... algoDigestPairs )
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
new file mode 100644
index 0000000..8ebddaa
--- /dev/null
+++ b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java
@@ -0,0 +1,124 @@
+package org.eclipse.aether.connector.basic;
+
+/*
+ * 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.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Set;
+
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithm;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySupport;
+import org.eclipse.aether.util.ChecksumUtils;
+
+/**
+ * Test implementation of {@link ChecksumAlgorithmFactorySelector}.
+ */
+public class TestChecksumAlgorithmSelector
+ implements ChecksumAlgorithmFactorySelector
+{
+ public static final String SHA512 = "SHA-512";
+
+ public static final String SHA256 = "SHA-256";
+
+ public static final String SHA1 = "SHA-1";
+
+ public static final String MD5 = "MD5";
+
+ public static final String TEST_CHECKSUM = "test";
+
+ public static final String TEST_CHECKSUM_VALUE = "01020304";
+
+ @Override
+ public Set<String> getChecksumAlgorithmNames()
+ {
+ return Collections.emptySet(); // irrelevant
+ }
+
+ @Override
+ public ChecksumAlgorithmFactory select( final String algorithm )
+ {
+ if ( TEST_CHECKSUM.equals( algorithm ) )
+ {
+ return new ChecksumAlgorithmFactorySupport( TEST_CHECKSUM, "test" )
+ {
+ @Override
+ public ChecksumAlgorithm getAlgorithm()
+ {
+ return new ChecksumAlgorithm()
+ {
+ @Override
+ public void update( final ByteBuffer input )
+ {
+
+ }
+
+ @Override
+ public String checksum()
+ {
+ return TEST_CHECKSUM_VALUE;
+ }
+ };
+ }
+ };
+ }
+ return new MessageDigestChecksumAlgorithmFactory( algorithm );
+ }
+
+ private static class MessageDigestChecksumAlgorithmFactory
+ extends ChecksumAlgorithmFactorySupport
+ {
+ public MessageDigestChecksumAlgorithmFactory( String name )
+ {
+ super( name, name.replace( "-", "" ).toLowerCase( Locale.ENGLISH ) );
+ }
+
+ @Override
+ public ChecksumAlgorithm getAlgorithm()
+ {
+ try
+ {
+ MessageDigest messageDigest = MessageDigest.getInstance( getName() );
+ return new ChecksumAlgorithm()
+ {
+ @Override
+ public void update( final ByteBuffer input )
+ {
+ messageDigest.update( input );
+ }
+
+ @Override
+ public String checksum()
+ {
+ return ChecksumUtils.toHexString( messageDigest.digest() );
+ }
+ };
+ }
+ catch ( NoSuchAlgorithmException e )
+ {
+ throw new IllegalArgumentException( "Algorithm '" + getName() + "' not supported." );
+ }
+ }
+ }
+}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java
index 037f302..c17e237 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java
@@ -35,6 +35,7 @@ import org.eclipse.aether.internal.impl.DefaultArtifactResolver;
import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider;
import org.eclipse.aether.internal.impl.DefaultTrackingFileManager;
import org.eclipse.aether.internal.impl.TrackingFileManager;
+import org.eclipse.aether.internal.impl.checksum.DefaultChecksumAlgorithmFactorySelector;
import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector;
import org.eclipse.aether.internal.impl.DefaultDeployer;
import org.eclipse.aether.internal.impl.DefaultFileProcessor;
@@ -57,6 +58,7 @@ import org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory;
import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory;
import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactorySelector;
import org.eclipse.aether.internal.impl.synccontext.named.SimpleNamedLockFactorySelector;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider;
@@ -224,6 +226,7 @@ public final class DefaultServiceLocator
addService( LoggerFactory.class, Slf4jLoggerFactory.class );
addService( TrackingFileManager.class, DefaultTrackingFileManager.class );
addService( NamedLockFactorySelector.class, SimpleNamedLockFactorySelector.class );
+ addService( ChecksumAlgorithmFactorySelector.class, DefaultChecksumAlgorithmFactorySelector.class );
}
private <T> Entry<T> getEntry( Class<T> type, boolean create )
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..c324fa9 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
@@ -42,6 +42,11 @@ 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.TrackingFileManager;
+import org.eclipse.aether.internal.impl.checksum.Md5ChecksumAlgorithmFactory;
+import org.eclipse.aether.internal.impl.checksum.Sha1ChecksumAlgorithmFactory;
+import org.eclipse.aether.internal.impl.checksum.Sha256ChecksumAlgorithmFactory;
+import org.eclipse.aether.internal.impl.checksum.Sha512ChecksumAlgorithmFactory;
+import org.eclipse.aether.internal.impl.checksum.DefaultChecksumAlgorithmFactorySelector;
import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory;
import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactorySelector;
import org.eclipse.aether.internal.impl.synccontext.named.SimpleNamedLockFactorySelector;
@@ -78,7 +83,9 @@ 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.ChecksumAlgorithmFactorySelector;
import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider;
import org.eclipse.aether.spi.connector.transport.TransporterProvider;
@@ -99,10 +106,10 @@ import com.google.inject.name.Names;
* repository connector and transporter factories to access remote repositories.
*
* @noextend This class must not be extended by clients and will eventually be marked {@code final} without prior
- * notice.
+ * notice.
*/
public class AetherModule
- extends AbstractModule
+ extends AbstractModule
{
/**
@@ -120,47 +127,58 @@ public class AetherModule
protected void configure()
{
bind( RepositorySystem.class ) //
- .to( DefaultRepositorySystem.class ).in( Singleton.class );
+ .to( DefaultRepositorySystem.class ).in( Singleton.class );
bind( ArtifactResolver.class ) //
- .to( DefaultArtifactResolver.class ).in( Singleton.class );
+ .to( DefaultArtifactResolver.class ).in( Singleton.class );
bind( DependencyCollector.class ) //
- .to( DefaultDependencyCollector.class ).in( Singleton.class );
+ .to( DefaultDependencyCollector.class ).in( Singleton.class );
bind( Deployer.class ) //
- .to( DefaultDeployer.class ).in( Singleton.class );
+ .to( DefaultDeployer.class ).in( Singleton.class );
bind( Installer.class ) //
- .to( DefaultInstaller.class ).in( Singleton.class );
+ .to( DefaultInstaller.class ).in( Singleton.class );
bind( MetadataResolver.class ) //
- .to( DefaultMetadataResolver.class ).in( Singleton.class );
+ .to( DefaultMetadataResolver.class ).in( Singleton.class );
bind( RepositoryLayoutProvider.class ) //
- .to( DefaultRepositoryLayoutProvider.class ).in( Singleton.class );
+ .to( DefaultRepositoryLayoutProvider.class ).in( Singleton.class );
bind( RepositoryLayoutFactory.class ).annotatedWith( Names.named( "maven2" ) ) //
- .to( Maven2RepositoryLayoutFactory.class ).in( Singleton.class );
+ .to( Maven2RepositoryLayoutFactory.class ).in( Singleton.class );
bind( TransporterProvider.class ) //
- .to( DefaultTransporterProvider.class ).in( Singleton.class );
+ .to( DefaultTransporterProvider.class ).in( Singleton.class );
bind( ChecksumPolicyProvider.class ) //
- .to( DefaultChecksumPolicyProvider.class ).in( Singleton.class );
+ .to( DefaultChecksumPolicyProvider.class ).in( Singleton.class );
bind( RepositoryConnectorProvider.class ) //
- .to( DefaultRepositoryConnectorProvider.class ).in( Singleton.class );
+ .to( DefaultRepositoryConnectorProvider.class ).in( Singleton.class );
bind( RemoteRepositoryManager.class ) //
- .to( DefaultRemoteRepositoryManager.class ).in( Singleton.class );
+ .to( DefaultRemoteRepositoryManager.class ).in( Singleton.class );
bind( UpdateCheckManager.class ) //
- .to( DefaultUpdateCheckManager.class ).in( Singleton.class );
+ .to( DefaultUpdateCheckManager.class ).in( Singleton.class );
bind( UpdatePolicyAnalyzer.class ) //
- .to( DefaultUpdatePolicyAnalyzer.class ).in( Singleton.class );
+ .to( DefaultUpdatePolicyAnalyzer.class ).in( Singleton.class );
bind( FileProcessor.class ) //
- .to( DefaultFileProcessor.class ).in( Singleton.class );
+ .to( DefaultFileProcessor.class ).in( Singleton.class );
bind( RepositoryEventDispatcher.class ) //
- .to( DefaultRepositoryEventDispatcher.class ).in( Singleton.class );
+ .to( DefaultRepositoryEventDispatcher.class ).in( Singleton.class );
bind( OfflineController.class ) //
- .to( DefaultOfflineController.class ).in( Singleton.class );
+ .to( DefaultOfflineController.class ).in( Singleton.class );
bind( LocalRepositoryProvider.class ) //
- .to( DefaultLocalRepositoryProvider.class ).in( Singleton.class );
+ .to( DefaultLocalRepositoryProvider.class ).in( Singleton.class );
bind( LocalRepositoryManagerFactory.class ).annotatedWith( Names.named( "simple" ) ) //
- .to( SimpleLocalRepositoryManagerFactory.class ).in( Singleton.class );
+ .to( SimpleLocalRepositoryManagerFactory.class ).in( Singleton.class );
bind( LocalRepositoryManagerFactory.class ).annotatedWith( Names.named( "enhanced" ) ) //
- .to( EnhancedLocalRepositoryManagerFactory.class ).in( Singleton.class );
+ .to( EnhancedLocalRepositoryManagerFactory.class ).in( Singleton.class );
bind( TrackingFileManager.class ).to( DefaultTrackingFileManager.class ).in( Singleton.class );
+ bind( ChecksumAlgorithmFactory.class ).annotatedWith( Names.named( Md5ChecksumAlgorithmFactory.NAME ) )
+ .to( Md5ChecksumAlgorithmFactory.class );
+ bind( ChecksumAlgorithmFactory.class ).annotatedWith( Names.named( Sha1ChecksumAlgorithmFactory.NAME ) )
+ .to( Sha1ChecksumAlgorithmFactory.class );
+ bind( ChecksumAlgorithmFactory.class ).annotatedWith( Names.named( Sha256ChecksumAlgorithmFactory.NAME ) )
+ .to( Sha256ChecksumAlgorithmFactory.class );
+ bind( ChecksumAlgorithmFactory.class ).annotatedWith( Names.named( Sha512ChecksumAlgorithmFactory.NAME ) )
+ .to( Sha512ChecksumAlgorithmFactory.class );
+ bind( ChecksumAlgorithmFactorySelector.class )
+ .to( DefaultChecksumAlgorithmFactorySelector.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 )
@@ -168,22 +186,22 @@ public class AetherModule
.in( Singleton.class );
bind( NameMapper.class ).annotatedWith( Names.named( StaticNameMapper.NAME ) )
- .to( StaticNameMapper.class ).in( Singleton.class );
+ .to( StaticNameMapper.class ).in( Singleton.class );
bind( NameMapper.class ).annotatedWith( Names.named( GAVNameMapper.NAME ) )
- .to( GAVNameMapper.class ).in( Singleton.class );
+ .to( GAVNameMapper.class ).in( Singleton.class );
bind( NameMapper.class ).annotatedWith( Names.named( DiscriminatingNameMapper.NAME ) )
- .to( DiscriminatingNameMapper.class ).in( Singleton.class );
+ .to( DiscriminatingNameMapper.class ).in( Singleton.class );
bind( NameMapper.class ).annotatedWith( Names.named( FileGAVNameMapper.NAME ) )
- .to( FileGAVNameMapper.class ).in( Singleton.class );
+ .to( FileGAVNameMapper.class ).in( Singleton.class );
bind( NamedLockFactory.class ).annotatedWith( Names.named( NoopNamedLockFactory.NAME ) )
- .to( NoopNamedLockFactory.class ).in( Singleton.class );
+ .to( NoopNamedLockFactory.class ).in( Singleton.class );
bind( NamedLockFactory.class ).annotatedWith( Names.named( LocalReadWriteLockNamedLockFactory.NAME ) )
- .to( LocalReadWriteLockNamedLockFactory.class ).in( Singleton.class );
+ .to( LocalReadWriteLockNamedLockFactory.class ).in( Singleton.class );
bind( NamedLockFactory.class ).annotatedWith( Names.named( LocalSemaphoreNamedLockFactory.NAME ) )
- .to( LocalSemaphoreNamedLockFactory.class ).in( Singleton.class );
+ .to( LocalSemaphoreNamedLockFactory.class ).in( Singleton.class );
bind( NamedLockFactory.class ).annotatedWith( Names.named( FileLockNamedLockFactory.NAME ) )
- .to( FileLockNamedLockFactory.class ).in( Singleton.class );
+ .to( FileLockNamedLockFactory.class ).in( Singleton.class );
install( new Slf4jModule() );
@@ -191,11 +209,27 @@ public class AetherModule
@Provides
@Singleton
+ Map<String, ChecksumAlgorithmFactory> provideChecksumTypes(
+ @Named( Sha512ChecksumAlgorithmFactory.NAME ) ChecksumAlgorithmFactory sha512,
+ @Named( Sha256ChecksumAlgorithmFactory.NAME ) ChecksumAlgorithmFactory sha256,
+ @Named( Sha1ChecksumAlgorithmFactory.NAME ) ChecksumAlgorithmFactory sha1,
+ @Named( Md5ChecksumAlgorithmFactory.NAME ) ChecksumAlgorithmFactory md5 )
+ {
+ Map<String, ChecksumAlgorithmFactory> checksumTypes = new HashMap<>();
+ checksumTypes.put( Sha512ChecksumAlgorithmFactory.NAME, sha512 );
+ checksumTypes.put( Sha256ChecksumAlgorithmFactory.NAME, sha256 );
+ checksumTypes.put( Sha1ChecksumAlgorithmFactory.NAME, sha1 );
+ checksumTypes.put( Md5ChecksumAlgorithmFactory.NAME, md5 );
+ return Collections.unmodifiableMap( checksumTypes );
+ }
+
+ @Provides
+ @Singleton
Map<String, NameMapper> provideNameMappers(
- @Named( StaticNameMapper.NAME ) NameMapper staticNameMapper,
- @Named( GAVNameMapper.NAME ) NameMapper gavNameMapper,
- @Named( DiscriminatingNameMapper.NAME ) NameMapper discriminatingNameMapper,
- @Named( FileGAVNameMapper.NAME ) NameMapper fileGavNameMapper )
+ @Named( StaticNameMapper.NAME ) NameMapper staticNameMapper,
+ @Named( GAVNameMapper.NAME ) NameMapper gavNameMapper,
+ @Named( DiscriminatingNameMapper.NAME ) NameMapper discriminatingNameMapper,
+ @Named( FileGAVNameMapper.NAME ) NameMapper fileGavNameMapper )
{
Map<String, NameMapper> nameMappers = new HashMap<>();
nameMappers.put( StaticNameMapper.NAME, staticNameMapper );
@@ -248,14 +282,14 @@ public class AetherModule
}
private static class Slf4jModule
- extends AbstractModule
+ extends AbstractModule
{
@Override
protected void configure()
{
bind( LoggerFactory.class ) //
- .to( Slf4jLoggerFactory.class );
+ .to( Slf4jLoggerFactory.class );
}
@Provides
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 32fb0a9..d5e1ecb 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
@@ -8,9 +8,9 @@ package org.eclipse.aether.internal.impl;
* 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
@@ -28,7 +28,7 @@ import org.slf4j.LoggerFactory;
import static java.util.Objects.requireNonNull;
abstract class AbstractChecksumPolicy
- implements ChecksumPolicy
+ implements ChecksumPolicy
{
protected final Logger logger = LoggerFactory.getLogger( getClass() );
@@ -40,14 +40,16 @@ abstract class AbstractChecksumPolicy
this.resource = resource;
}
+ @Override
public boolean onChecksumMatch( String algorithm, int kind )
{
requireNonNull( algorithm, "algorithm cannot be null" );
return true;
}
+ @Override
public void onChecksumMismatch( String algorithm, int kind, ChecksumFailureException exception )
- throws ChecksumFailureException
+ throws ChecksumFailureException
{
requireNonNull( algorithm, "algorithm cannot be null" );
requireNonNull( exception, "exception cannot be null" );
@@ -57,20 +59,23 @@ abstract class AbstractChecksumPolicy
}
}
+ @Override
public void onChecksumError( String algorithm, int kind, ChecksumFailureException exception )
- throws ChecksumFailureException
+ throws ChecksumFailureException
{
requireNonNull( algorithm, "algorithm cannot be null" );
requireNonNull( exception, "exception cannot be null" );
logger.debug( "Could not validate {} checksum for {}", algorithm, resource.getResourceName(), exception );
}
+ @Override
public void onNoMoreChecksums()
- throws ChecksumFailureException
+ throws ChecksumFailureException
{
throw new ChecksumFailureException( "Checksum validation failed, no checksums available" );
}
+ @Override
public void onTransferRetry()
{
}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java
index 99d5861..3aebd78 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java
@@ -25,7 +25,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
@@ -33,6 +32,7 @@ import javax.inject.Named;
import javax.inject.Singleton;
import org.eclipse.aether.spi.io.FileProcessor;
+import org.eclipse.aether.util.ChecksumUtils;
/**
* A utility class helping with file-based operations.
@@ -212,19 +212,16 @@ public class DefaultFileProcessor
throws IOException
{
long total = 0L;
-
- ByteBuffer buffer = ByteBuffer.allocate( 1024 * 32 );
- byte[] array = buffer.array();
-
+ byte[] buffer = new byte[ 1024 * 32 ];
while ( true )
{
- int bytes = is.read( array );
+ int bytes = is.read( buffer );
if ( bytes < 0 )
{
break;
}
- os.write( array, 0, bytes );
+ os.write( buffer, 0, bytes );
total += bytes;
@@ -232,9 +229,7 @@ public class DefaultFileProcessor
{
try
{
- ( (Buffer) buffer ).rewind();
- ( (Buffer) buffer ).limit( bytes );
- listener.progressed( buffer );
+ listener.progressed( ByteBuffer.wrap( buffer, 0, bytes ) );
}
catch ( Exception e )
{
@@ -259,4 +254,17 @@ public class DefaultFileProcessor
}
}
+ @Override
+ public String readChecksum( final File checksumFile ) throws IOException
+ {
+ // for now do exactly same as happened before, but FileProcessor is a component and can be replaced
+ return ChecksumUtils.read( checksumFile );
+ }
+
+ @Override
+ public void writeChecksum( final File checksumFile, final String checksum ) throws IOException
+ {
+ // for now do exactly same as happened before, but FileProcessor is a component and can be replaced
+ write( checksumFile, checksum );
+ }
}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java
index c19c006..70d36c6 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java
@@ -34,6 +34,7 @@ final class FailChecksumPolicy
super( resource );
}
+ @Override
public boolean onTransferChecksumFailure( ChecksumFailureException error )
{
return false;
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..3715196 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
@@ -21,18 +21,24 @@ package org.eclipse.aether.internal.impl;
import java.net.URI;
import java.net.URISyntaxException;
-import java.util.Arrays;
import java.util.ArrayList;
+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;
import javax.inject.Singleton;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.internal.impl.checksum.DefaultChecksumAlgorithmFactorySelector;
import org.eclipse.aether.metadata.Metadata;
import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
import org.eclipse.aether.spi.connector.layout.RepositoryLayout;
import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory;
import org.eclipse.aether.transfer.NoRepositoryLayoutException;
@@ -46,7 +52,7 @@ import static java.util.Objects.requireNonNull;
@Singleton
@Named( "maven2" )
public final class Maven2RepositoryLayoutFactory
- implements RepositoryLayoutFactory
+ implements RepositoryLayoutFactory
{
static final String CONFIG_PROP_SIGNATURE_CHECKSUMS = "aether.checksums.forSignature";
@@ -56,12 +62,29 @@ public final class Maven2RepositoryLayoutFactory
private float priority;
+ private final ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector;
+
public float getPriority()
{
return priority;
}
/**
+ * Service locator ctor.
+ */
+ @Deprecated
+ public Maven2RepositoryLayoutFactory()
+ {
+ this( new DefaultChecksumAlgorithmFactorySelector() );
+ }
+
+ @Inject
+ public Maven2RepositoryLayoutFactory( ChecksumAlgorithmFactorySelector checksumAlgorithmFactorySelector )
+ {
+ this.checksumAlgorithmFactorySelector = requireNonNull( checksumAlgorithmFactorySelector );
+ }
+
+ /**
* Sets the priority of this component.
*
* @param priority The priority.
@@ -74,7 +97,7 @@ public final class Maven2RepositoryLayoutFactory
}
public RepositoryLayout newInstance( RepositorySystemSession session, RemoteRepository repository )
- throws NoRepositoryLayoutException
+ throws NoRepositoryLayoutException
{
requireNonNull( session, "session cannot be null" );
requireNonNull( repository, "repository cannot be null" );
@@ -83,8 +106,18 @@ public final class Maven2RepositoryLayoutFactory
throw new NoRepositoryLayoutException( repository );
}
boolean forSignature = ConfigUtils.getBoolean( session, false, CONFIG_PROP_SIGNATURE_CHECKSUMS );
- List<String> checksumsAlgorithms = Arrays.asList( ConfigUtils.getString( session,
- DEFAULT_CHECKSUMS_ALGORITHMS, CONFIG_PROP_CHECKSUMS_ALGORITHMS ).split( "," ) );
+ // ensure order of (potentially user set) algorithm list is kept and is unique
+ LinkedHashSet<String> checksumsAlgorithmNames = new LinkedHashSet<>( Arrays.asList(
+ ConfigUtils.getString(
+ session, DEFAULT_CHECKSUMS_ALGORITHMS, CONFIG_PROP_CHECKSUMS_ALGORITHMS
+ ).split( "," ) )
+ );
+
+ List<ChecksumAlgorithmFactory> checksumsAlgorithms = new ArrayList<>( checksumsAlgorithmNames.size() );
+ for ( String checksumsAlgorithmName : checksumsAlgorithmNames )
+ {
+ checksumsAlgorithms.add( checksumAlgorithmFactorySelector.select( checksumsAlgorithmName ) );
+ }
return forSignature
? new Maven2RepositoryLayout( checksumsAlgorithms )
@@ -92,14 +125,14 @@ public final class Maven2RepositoryLayoutFactory
}
private static class Maven2RepositoryLayout
- implements RepositoryLayout
+ implements RepositoryLayout
{
- private final List<String> checksumsAlgorithms;
+ private final List<ChecksumAlgorithmFactory> checksumAlgorithms;
- protected Maven2RepositoryLayout( List<String> checksumsAlgorithms )
+ protected Maven2RepositoryLayout( List<ChecksumAlgorithmFactory> checksumAlgorithms )
{
- this.checksumsAlgorithms = checksumsAlgorithms;
+ this.checksumAlgorithms = Collections.unmodifiableList( checksumAlgorithms );
}
private URI toUri( String path )
@@ -114,6 +147,13 @@ public final class Maven2RepositoryLayoutFactory
}
}
+ @Override
+ public List<String> getChecksumAlgorithmNames()
+ {
+ return checksumAlgorithms.stream().map( ChecksumAlgorithmFactory::getName ).collect( Collectors.toList() );
+ }
+
+ @Override
public URI getLocation( Artifact artifact, boolean upload )
{
StringBuilder path = new StringBuilder( 128 );
@@ -139,6 +179,7 @@ public final class Maven2RepositoryLayoutFactory
return toUri( path.toString() );
}
+ @Override
public URI getLocation( Metadata metadata, boolean upload )
{
StringBuilder path = new StringBuilder( 128 );
@@ -163,45 +204,47 @@ public final class Maven2RepositoryLayoutFactory
return toUri( path.toString() );
}
- public List<Checksum> getChecksums( Artifact artifact, boolean upload, URI location )
+ @Override
+ public List<ChecksumLocation> getChecksumLocations( Artifact artifact, boolean upload, URI location )
{
- return getChecksums( location );
+ return getChecksumLocations( location );
}
- public List<Checksum> getChecksums( Metadata metadata, boolean upload, URI location )
+ @Override
+ public List<ChecksumLocation> getChecksumLocations( Metadata metadata, boolean upload, URI location )
{
- return getChecksums( location );
+ return getChecksumLocations( location );
}
- private List<Checksum> getChecksums( URI location )
+ private List<ChecksumLocation> getChecksumLocations( URI location )
{
- List<Checksum> checksums = new ArrayList<>( checksumsAlgorithms.size() );
- for ( String algorithm : checksumsAlgorithms )
+ List<ChecksumLocation> checksumLocations = new ArrayList<>( checksumAlgorithms.size() );
+ for ( ChecksumAlgorithmFactory checksumAlgorithmFactory : checksumAlgorithms )
{
- checksums.add( Checksum.forLocation( location, algorithm ) );
+ checksumLocations.add( ChecksumLocation.forLocation( location, checksumAlgorithmFactory ) );
}
- return checksums;
+ return checksumLocations;
}
}
private static class Maven2RepositoryLayoutEx
- extends Maven2RepositoryLayout
+ extends Maven2RepositoryLayout
{
- protected Maven2RepositoryLayoutEx( List<String> checksumsAlgorithms )
+ protected Maven2RepositoryLayoutEx( List<ChecksumAlgorithmFactory> checksumAlgorithms )
{
- super( checksumsAlgorithms );
+ super( checksumAlgorithms );
}
@Override
- public List<Checksum> getChecksums( Artifact artifact, boolean upload, URI location )
+ public List<ChecksumLocation> getChecksumLocations( Artifact artifact, boolean upload, URI location )
{
if ( isSignature( artifact.getExtension() ) )
{
return Collections.emptyList();
}
- return super.getChecksums( artifact, upload, location );
+ return super.getChecksumLocations( artifact, upload, location );
}
private boolean isSignature( String extension )
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/WarnChecksumPolicy.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/WarnChecksumPolicy.java
index fca0671..ff8ac4f 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/WarnChecksumPolicy.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/WarnChecksumPolicy.java
@@ -34,6 +34,7 @@ final class WarnChecksumPolicy
super( resource );
}
+ @Override
public boolean onTransferChecksumFailure( ChecksumFailureException exception )
{
logger.warn( "Could not validate integrity of download from {}{}", resource.getRepositoryUrl(),
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
new file mode 100644
index 0000000..3e6d657
--- /dev/null
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector.java
@@ -0,0 +1,87 @@
+package org.eclipse.aether.internal.impl.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 javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.HashMap;
+import java.util.HashSet;
+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;
+
+/**
+ * Default implementation.
+ *
+ * @since 1.8.0
+ */
+@Singleton
+@Named
+public class DefaultChecksumAlgorithmFactorySelector
+ implements ChecksumAlgorithmFactorySelector
+{
+ private final Map<String, ChecksumAlgorithmFactory> factories;
+
+ /**
+ * Default ctor for SL.
+ */
+ @Deprecated
+ public DefaultChecksumAlgorithmFactorySelector()
+ {
+ this.factories = new HashMap<>();
+ this.factories.put( Sha512ChecksumAlgorithmFactory.NAME, new Sha512ChecksumAlgorithmFactory() );
+ this.factories.put( Sha256ChecksumAlgorithmFactory.NAME, new Sha256ChecksumAlgorithmFactory() );
+ this.factories.put( Sha1ChecksumAlgorithmFactory.NAME, new Sha1ChecksumAlgorithmFactory() );
+ this.factories.put( Md5ChecksumAlgorithmFactory.NAME, new Md5ChecksumAlgorithmFactory() );
+ }
+
+ @Inject
+ public DefaultChecksumAlgorithmFactorySelector( Map<String, ChecksumAlgorithmFactory> factories )
+ {
+ this.factories = requireNonNull( factories );
+ }
+
+ @Override
+ public ChecksumAlgorithmFactory select( String algorithmName )
+ {
+ requireNonNull( algorithmName, "algorithmMame must not be null" );
+ ChecksumAlgorithmFactory factory = factories.get( algorithmName );
+ if ( factory == null )
+ {
+ throw new IllegalArgumentException(
+ String.format( "Unsupported checksum algorithm %s, supported ones are %s",
+ algorithmName, getChecksumAlgorithmNames() )
+ );
+ }
+ return factory;
+ }
+
+ @Override
+ public Set<String> getChecksumAlgorithmNames()
+ {
+ return new HashSet<>( factories.keySet() );
+ }
+}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Md5ChecksumAlgorithmFactory.java
similarity index 61%
copy from maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java
copy to maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Md5ChecksumAlgorithmFactory.java
index c19c006..4c6faf8 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Md5ChecksumAlgorithmFactory.java
@@ -1,4 +1,4 @@
-package org.eclipse.aether.internal.impl;
+package org.eclipse.aether.internal.impl.checksum;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -8,9 +8,9 @@ package org.eclipse.aether.internal.impl;
* 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
@@ -19,24 +19,25 @@ package org.eclipse.aether.internal.impl;
* under the License.
*/
-import org.eclipse.aether.transfer.ChecksumFailureException;
-import org.eclipse.aether.transfer.TransferResource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
/**
- * Implements {@link org.eclipse.aether.repository.RepositoryPolicy#CHECKSUM_POLICY_FAIL}.
+ * The MD5 checksum type.
+ *
+ * @since 1.8.0
*/
-final class FailChecksumPolicy
- extends AbstractChecksumPolicy
+@Singleton
+@Named( Md5ChecksumAlgorithmFactory.NAME )
+public class Md5ChecksumAlgorithmFactory
+ extends MessageDigestChecksumAlgorithmFactorySupport
{
+ public static final String NAME = "MD5";
- FailChecksumPolicy( TransferResource resource )
+ @Inject
+ public Md5ChecksumAlgorithmFactory()
{
- super( resource );
+ super( NAME, "md5" );
}
-
- public boolean onTransferChecksumFailure( ChecksumFailureException error )
- {
- return false;
- }
-
}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/MessageDigestChecksumAlgorithmFactorySupport.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/MessageDigestChecksumAlgorithmFactorySupport.java
new file mode 100644
index 0000000..a285f5e
--- /dev/null
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/MessageDigestChecksumAlgorithmFactorySupport.java
@@ -0,0 +1,71 @@
+package org.eclipse.aether.internal.impl.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 org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithm;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySupport;
+import org.eclipse.aether.util.ChecksumUtils;
+
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Support class to implement {@link ChecksumAlgorithmFactory} based on Java {@link MessageDigest}.
+ *
+ * @since 1.8.0
+ */
+public abstract class MessageDigestChecksumAlgorithmFactorySupport
+ extends ChecksumAlgorithmFactorySupport
+{
+ public MessageDigestChecksumAlgorithmFactorySupport( String name, String extension )
+ {
+ super( name, extension );
+ }
+
+ @Override
+ public ChecksumAlgorithm getAlgorithm()
+ {
+ try
+ {
+ MessageDigest messageDigest = MessageDigest.getInstance( getName() );
+ return new ChecksumAlgorithm()
+ {
+ @Override
+ public void update( final ByteBuffer input )
+ {
+ messageDigest.update( input );
+ }
+
+ @Override
+ public String checksum()
+ {
+ return ChecksumUtils.toHexString( messageDigest.digest() );
+ }
+ };
+ }
+ catch ( NoSuchAlgorithmException e )
+ {
+ throw new IllegalStateException(
+ "MessageDigest algorithm " + getName() + " not supported, but is required by resolver.", e );
+ }
+ }
+}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Sha1ChecksumAlgorithmFactory.java
similarity index 61%
copy from maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java
copy to maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Sha1ChecksumAlgorithmFactory.java
index c19c006..aef57fe 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Sha1ChecksumAlgorithmFactory.java
@@ -1,4 +1,4 @@
-package org.eclipse.aether.internal.impl;
+package org.eclipse.aether.internal.impl.checksum;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -8,9 +8,9 @@ package org.eclipse.aether.internal.impl;
* 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
@@ -19,24 +19,25 @@ package org.eclipse.aether.internal.impl;
* under the License.
*/
-import org.eclipse.aether.transfer.ChecksumFailureException;
-import org.eclipse.aether.transfer.TransferResource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
/**
- * Implements {@link org.eclipse.aether.repository.RepositoryPolicy#CHECKSUM_POLICY_FAIL}.
+ * The SHA-1 checksum type.
+ *
+ * @since 1.8.0
*/
-final class FailChecksumPolicy
- extends AbstractChecksumPolicy
+@Singleton
+@Named( Sha1ChecksumAlgorithmFactory.NAME )
+public class Sha1ChecksumAlgorithmFactory
+ extends MessageDigestChecksumAlgorithmFactorySupport
{
+ public static final String NAME = "SHA-1";
- FailChecksumPolicy( TransferResource resource )
+ @Inject
+ public Sha1ChecksumAlgorithmFactory()
{
- super( resource );
+ super( NAME, "sha1" );
}
-
- public boolean onTransferChecksumFailure( ChecksumFailureException error )
- {
- return false;
- }
-
}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Sha256ChecksumAlgorithmFactory.java
similarity index 61%
copy from maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java
copy to maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Sha256ChecksumAlgorithmFactory.java
index c19c006..35d00cf 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Sha256ChecksumAlgorithmFactory.java
@@ -1,4 +1,4 @@
-package org.eclipse.aether.internal.impl;
+package org.eclipse.aether.internal.impl.checksum;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -8,9 +8,9 @@ package org.eclipse.aether.internal.impl;
* 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
@@ -19,24 +19,25 @@ package org.eclipse.aether.internal.impl;
* under the License.
*/
-import org.eclipse.aether.transfer.ChecksumFailureException;
-import org.eclipse.aether.transfer.TransferResource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
/**
- * Implements {@link org.eclipse.aether.repository.RepositoryPolicy#CHECKSUM_POLICY_FAIL}.
+ * The SHA-256 checksum type.
+ *
+ * @since 1.8.0
*/
-final class FailChecksumPolicy
- extends AbstractChecksumPolicy
+@Singleton
+@Named( Sha256ChecksumAlgorithmFactory.NAME )
+public class Sha256ChecksumAlgorithmFactory
+ extends MessageDigestChecksumAlgorithmFactorySupport
{
+ public static final String NAME = "SHA-256";
- FailChecksumPolicy( TransferResource resource )
+ @Inject
+ public Sha256ChecksumAlgorithmFactory()
{
- super( resource );
+ super( NAME, "sha256" );
}
-
- public boolean onTransferChecksumFailure( ChecksumFailureException error )
- {
- return false;
- }
-
}
diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Sha512ChecksumAlgorithmFactory.java
similarity index 61%
copy from maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java
copy to maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Sha512ChecksumAlgorithmFactory.java
index c19c006..0c60862 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/FailChecksumPolicy.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/Sha512ChecksumAlgorithmFactory.java
@@ -1,4 +1,4 @@
-package org.eclipse.aether.internal.impl;
+package org.eclipse.aether.internal.impl.checksum;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -8,9 +8,9 @@ package org.eclipse.aether.internal.impl;
* 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
@@ -19,24 +19,25 @@ package org.eclipse.aether.internal.impl;
* under the License.
*/
-import org.eclipse.aether.transfer.ChecksumFailureException;
-import org.eclipse.aether.transfer.TransferResource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
/**
- * Implements {@link org.eclipse.aether.repository.RepositoryPolicy#CHECKSUM_POLICY_FAIL}.
+ * The SHA-512 checksum type.
+ *
+ * @since 1.8.0
*/
-final class FailChecksumPolicy
- extends AbstractChecksumPolicy
+@Singleton
+@Named( Sha512ChecksumAlgorithmFactory.NAME )
+public class Sha512ChecksumAlgorithmFactory
+ extends MessageDigestChecksumAlgorithmFactorySupport
{
+ public static final String NAME = "SHA-512";
- FailChecksumPolicy( TransferResource resource )
+ @Inject
+ public Sha512ChecksumAlgorithmFactory()
{
- super( resource );
+ super( NAME, "sha512" );
}
-
- public boolean onTransferChecksumFailure( ChecksumFailureException error )
- {
- return false;
- }
-
}
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 3720509..311607c 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
@@ -22,8 +22,8 @@ package org.eclipse.aether.internal.impl;
import static org.junit.Assert.*;
import java.net.URI;
+import java.util.Arrays;
import java.util.List;
-import java.util.Locale;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.artifact.DefaultArtifact;
@@ -31,14 +31,44 @@ import org.eclipse.aether.internal.test.util.TestUtils;
import org.eclipse.aether.metadata.DefaultMetadata;
import org.eclipse.aether.metadata.Metadata;
import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithm;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySupport;
import org.eclipse.aether.spi.connector.layout.RepositoryLayout;
-import org.eclipse.aether.spi.connector.layout.RepositoryLayout.Checksum;
+import org.eclipse.aether.spi.connector.layout.RepositoryLayout.ChecksumLocation;
import org.eclipse.aether.transfer.NoRepositoryLayoutException;
import org.junit.Before;
import org.junit.Test;
public class Maven2RepositoryLayoutFactoryTest
{
+ private final ChecksumAlgorithmFactory SHA512 = new ChecksumAlgorithmFactorySupport("SHA-512", "sha512") {
+ @Override
+ public ChecksumAlgorithm getAlgorithm() {
+ throw new RuntimeException("this should not happen");
+ }
+ };
+
+ private final ChecksumAlgorithmFactory SHA256 = new ChecksumAlgorithmFactorySupport("SHA-256", "sha256") {
+ @Override
+ public ChecksumAlgorithm getAlgorithm() {
+ throw new RuntimeException("this should not happen");
+ }
+ };
+
+ private final ChecksumAlgorithmFactory SHA1 = new ChecksumAlgorithmFactorySupport("SHA-1", "sha1") {
+ @Override
+ public ChecksumAlgorithm getAlgorithm() {
+ throw new RuntimeException("this should not happen");
+ }
+ };
+
+ private final ChecksumAlgorithmFactory MD5 = new ChecksumAlgorithmFactorySupport("MD5", "md5") {
+ @Override
+ public ChecksumAlgorithm getAlgorithm() {
+ throw new RuntimeException("this should not happen");
+ }
+ };
private DefaultRepositorySystemSession session;
@@ -51,18 +81,23 @@ public class Maven2RepositoryLayoutFactoryTest
return new RemoteRepository.Builder( "test", type, "classpath:/nil" ).build();
}
- private void assertChecksum( Checksum actual, String expectedUri, String expectedAlgo )
+ private void assertChecksum( ChecksumLocation actual, String expectedUri, String expectedAlgo )
{
assertEquals( expectedUri, actual.getLocation().toString() );
- assertEquals( expectedAlgo, actual.getAlgorithm() );
+ assertEquals( expectedAlgo, actual.getChecksumAlgorithmFactory().getName() );
+ }
+
+ private void assertChecksum( ChecksumLocation actual, String expectedUri, ChecksumAlgorithmFactory expectedAlgorithmFactory )
+ {
+ assertChecksum( actual, expectedUri, expectedAlgorithmFactory.getName() );
}
- private void assertChecksums( List<Checksum> actual, String baseUri, String... algos )
+ private void assertChecksums( List<ChecksumLocation> actual, String baseUri, ChecksumAlgorithmFactory... algos )
{
assertEquals( algos.length, actual.size() );
for ( int i = 0; i < algos.length; i++ )
{
- String uri = baseUri + '.' + algos[i].replace( "-", "" ).toLowerCase( Locale.ENGLISH );
+ String uri = baseUri + '.' + algos[i].getFileExtension();
assertChecksum( actual.get( i ), uri, algos[i] );
}
}
@@ -84,6 +119,12 @@ public class Maven2RepositoryLayoutFactoryTest
}
@Test
+ public void testChecksumAlgorithmNames()
+ {
+ assertEquals( Arrays.asList( "SHA-1", "MD5" ), layout.getChecksumAlgorithmNames() );
+ }
+
+ @Test
public void testArtifactLocation_Release()
{
DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "ext", "1.0" );
@@ -153,10 +194,10 @@ public class Maven2RepositoryLayoutFactoryTest
{
DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "ext", "1.0" );
URI uri = layout.getLocation( artifact, false );
- List<Checksum> checksums = layout.getChecksums( artifact, false, uri );
+ List<ChecksumLocation> checksums = layout.getChecksumLocations( artifact, false, uri );
assertEquals( 2, checksums.size() );
- assertChecksum( checksums.get( 0 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha1", "SHA-1" );
- assertChecksum( checksums.get( 1 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.md5", "MD5" );
+ assertChecksum( checksums.get( 0 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha1", SHA1 );
+ assertChecksum( checksums.get( 1 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.md5", MD5 );
}
@Test
@@ -166,10 +207,17 @@ public class Maven2RepositoryLayoutFactoryTest
layout = factory.newInstance( session, newRepo( "default" ) );
DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "ext", "1.0" );
URI uri = layout.getLocation( artifact, false );
- List<Checksum> checksums = layout.getChecksums( artifact, false, uri );
+ List<ChecksumLocation> checksums = layout.getChecksumLocations( artifact, false, uri );
assertEquals( 2, checksums.size() );
- assertChecksum( checksums.get( 0 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha256", "SHA-256" );
- assertChecksum( checksums.get( 1 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha1", "SHA-1" );
+ assertChecksum( checksums.get( 0 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha256", SHA256 );
+ assertChecksum( checksums.get( 1 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha1", SHA1 );
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void testArtifactChecksums_DownloadWithUnsupportedAlgorithms() throws NoRepositoryLayoutException
+ {
+ session.setConfigProperty( Maven2RepositoryLayoutFactory.CONFIG_PROP_CHECKSUMS_ALGORITHMS, "FOO,SHA-1");
+ layout = factory.newInstance( session, newRepo( "default" ) );
}
@Test
@@ -177,10 +225,10 @@ public class Maven2RepositoryLayoutFactoryTest
{
DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "ext", "1.0" );
URI uri = layout.getLocation( artifact, true );
- List<Checksum> checksums = layout.getChecksums( artifact, true, uri );
+ List<ChecksumLocation> checksums = layout.getChecksumLocations( artifact, true, uri );
assertEquals( 2, checksums.size() );
- assertChecksum( checksums.get( 0 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha1", "SHA-1" );
- assertChecksum( checksums.get( 1 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.md5", "MD5" );
+ assertChecksum( checksums.get( 0 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha1", SHA1 );
+ assertChecksum( checksums.get( 1 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.md5", MD5 );
}
@Test
@@ -190,10 +238,10 @@ public class Maven2RepositoryLayoutFactoryTest
layout = factory.newInstance( session, newRepo( "default" ) );
DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "ext", "1.0" );
URI uri = layout.getLocation( artifact, true );
- List<Checksum> checksums = layout.getChecksums( artifact, true, uri );
+ List<ChecksumLocation> checksums = layout.getChecksumLocations( artifact, true, uri );
assertEquals( 2, checksums.size() );
- assertChecksum( checksums.get( 0 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha512", "SHA-512" );
- assertChecksum( checksums.get( 1 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.md5", "MD5" );
+ assertChecksum( checksums.get( 0 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.sha512", SHA512 );
+ assertChecksum( checksums.get( 1 ), "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.ext.md5", MD5 );
}
@Test
@@ -203,11 +251,12 @@ public class Maven2RepositoryLayoutFactoryTest
new DefaultMetadata( "org.apache.maven.plugins", "maven-jar-plugin", "maven-metadata.xml",
Metadata.Nature.RELEASE_OR_SNAPSHOT );
URI uri = layout.getLocation( metadata, false );
- List<Checksum> checksums = layout.getChecksums( metadata, false, uri );
+ List<ChecksumLocation> checksums = layout.getChecksumLocations( metadata, false, uri );
assertEquals( 2, checksums.size() );
assertChecksum( checksums.get( 0 ), "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml.sha1",
- "SHA-1" );
- assertChecksum( checksums.get( 1 ), "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml.md5", "MD5" );
+ SHA1 );
+ assertChecksum( checksums.get( 1 ), "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml.md5",
+ MD5 );
}
@Test
@@ -217,11 +266,12 @@ public class Maven2RepositoryLayoutFactoryTest
new DefaultMetadata( "org.apache.maven.plugins", "maven-jar-plugin", "maven-metadata.xml",
Metadata.Nature.RELEASE_OR_SNAPSHOT );
URI uri = layout.getLocation( metadata, true );
- List<Checksum> checksums = layout.getChecksums( metadata, true, uri );
+ List<ChecksumLocation> checksums = layout.getChecksumLocations( metadata, true, uri );
assertEquals( 2, checksums.size() );
assertChecksum( checksums.get( 0 ), "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml.sha1",
- "SHA-1" );
- assertChecksum( checksums.get( 1 ), "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml.md5", "MD5" );
+ SHA1 );
+ assertChecksum( checksums.get( 1 ), "org/apache/maven/plugins/maven-jar-plugin/maven-metadata.xml.md5",
+ MD5 );
}
@Test
@@ -229,12 +279,12 @@ public class Maven2RepositoryLayoutFactoryTest
{
DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "asc", "1.0" );
URI uri = layout.getLocation( artifact, false );
- List<Checksum> checksums = layout.getChecksums( artifact, false, uri );
- assertChecksums( checksums, "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.asc", "SHA-1", "MD5" );
+ List<ChecksumLocation> checksums = layout.getChecksumLocations( artifact, false, uri );
+ assertChecksums( checksums, "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.asc", SHA1, MD5 );
artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "jar.asc", "1.0" );
uri = layout.getLocation( artifact, false );
- checksums = layout.getChecksums( artifact, false, uri );
+ checksums = layout.getChecksumLocations( artifact, false, uri );
assertEquals( 0, checksums.size() );
}
@@ -243,12 +293,12 @@ public class Maven2RepositoryLayoutFactoryTest
{
DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "asc", "1.0" );
URI uri = layout.getLocation( artifact, true );
- List<Checksum> checksums = layout.getChecksums( artifact, true, uri );
- assertChecksums( checksums, "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.asc", "SHA-1", "MD5" );
+ List<ChecksumLocation> checksums = layout.getChecksumLocations( artifact, true, uri );
+ assertChecksums( checksums, "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.asc", SHA1, MD5 );
artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "jar.asc", "1.0" );
uri = layout.getLocation( artifact, true );
- checksums = layout.getChecksums( artifact, true, uri );
+ checksums = layout.getChecksumLocations( artifact, true, uri );
assertEquals( 0, checksums.size() );
}
@@ -260,8 +310,8 @@ public class Maven2RepositoryLayoutFactoryTest
layout = factory.newInstance( session, newRepo( "default" ) );
DefaultArtifact artifact = new DefaultArtifact( "g.i.d", "a-i.d", "cls", "jar.asc", "1.0" );
URI uri = layout.getLocation( artifact, true );
- List<Checksum> checksums = layout.getChecksums( artifact, true, uri );
- assertChecksums( checksums, "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.jar.asc", "SHA-1", "MD5" );
+ List<ChecksumLocation> checksums = layout.getChecksumLocations( artifact, true, uri );
+ assertChecksums( checksums, "g/i/d/a-i.d/1.0/a-i.d-1.0-cls.jar.asc", SHA1, MD5 );
}
}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithm.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithm.java
new file mode 100644
index 0000000..ade3c62
--- /dev/null
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithm.java
@@ -0,0 +1,46 @@
+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.nio.ByteBuffer;
+
+/**
+ * Implementation performing checksum calculation for specific algorithm. Instances of this interface are stateful,
+ * non-thread safe, and should not be reused.
+ *
+ * @since 1.8.0
+ */
+public interface ChecksumAlgorithm
+{
+ /**
+ * Updates the checksum algorithm inner state with input.
+ */
+ void update( ByteBuffer input );
+
+ /**
+ * Returns the algorithm end result as string, never {@code null}. After invoking this method, this instance should
+ * be discarded and not reused. For new checksum calculation you have to get new instance.
+ *
+ * Values returned by this method are handled as "opaque strings", and are used for simple equality checks (matches
+ * or not matches the checksum), and are also persisted in this form (locally to file system but also uploaded as
+ * checksum files). Resolver itself never tries to "decode" or "interpret" this string in any other way.
+ */
+ String checksum();
+}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactory.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactory.java
new file mode 100644
index 0000000..f8196d0
--- /dev/null
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactory.java
@@ -0,0 +1,48 @@
+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.
+ */
+
+/**
+ * A component representing a checksum factory: provides {@link ChecksumAlgorithm} instances, name and extension to be
+ * used with this algorithm. While directly injecting components of this type is possible, it is not recommended. To
+ * obtain factory instances use {@link ChecksumAlgorithmFactorySelector} instead.
+ *
+ * @since 1.8.0
+ */
+public interface ChecksumAlgorithmFactory
+{
+ /**
+ * Returns the algorithm name, usually used as key, never {@code null} value. The name is a standard name of
+ * algorithm (if applicable) or any other designator that is algorithm commonly referred with. Example: "SHA-1".
+ */
+ String getName();
+
+ /**
+ * Returns the file extension to be used for given checksum file (without leading dot), never {@code null}. The
+ * extension should be file and URL path friendly, and may differ from value returned by {@link #getName()}.
+ * Example: "sha1".
+ */
+ String getFileExtension();
+
+ /**
+ * Each invocation of this method returns a new instance of algorithm, never {@code null} value.
+ */
+ ChecksumAlgorithm getAlgorithm();
+}
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
new file mode 100644
index 0000000..eece32e
--- /dev/null
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector.java
@@ -0,0 +1,44 @@
+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.Set;
+
+/**
+ * Component performing selection of {@link ChecksumAlgorithmFactory} based on known factory names.
+ *
+ * @since 1.8.0
+ */
+public interface ChecksumAlgorithmFactorySelector
+{
+ /**
+ * Returns factory for given algorithm name, or throws if algorithm not supported.
+ *
+ * @throws IllegalArgumentException if asked algorithm name is not supported.
+ */
+ 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).
+ */
+ Set<String> getChecksumAlgorithmNames();
+}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySupport.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySupport.java
new file mode 100644
index 0000000..7fd398e
--- /dev/null
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySupport.java
@@ -0,0 +1,59 @@
+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 static java.util.Objects.requireNonNull;
+
+/**
+ * Support class for {@link ChecksumAlgorithmFactory} implementations.
+ *
+ * @since 1.8.0
+ */
+public abstract class ChecksumAlgorithmFactorySupport
+ implements ChecksumAlgorithmFactory
+{
+ private final String name;
+
+ private final String fileExtension;
+
+ public ChecksumAlgorithmFactorySupport( String name, String fileExtension )
+ {
+ this.name = requireNonNull( name );
+ this.fileExtension = requireNonNull( fileExtension );
+ }
+
+ /**
+ * Returns the algorithm name, usually used as key, never {@code null} value.
+ */
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Returns the file extension to be used for given checksum algorithm (without leading dot), never {@code null}.
+ */
+ @Override
+ public String getFileExtension()
+ {
+ return fileExtension;
+ }
+}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmHelper.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmHelper.java
new file mode 100644
index 0000000..5238dbb
--- /dev/null
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmHelper.java
@@ -0,0 +1,103 @@
+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.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper for checksum operations.
+ *
+ * @since 1.8.0
+ */
+public final class ChecksumAlgorithmHelper
+{
+ private ChecksumAlgorithmHelper()
+ {
+ // nop
+ }
+
+ /**
+ * Calculates checksums for specified data.
+ *
+ * @param data The content for which to calculate checksums, must not be {@code null}.
+ * @param factories The checksum algorithm factories to use, must not be {@code null}.
+ * @return The calculated checksums, indexed by algorithm name, or the exception that occurred while trying to
+ * calculate it, never {@code null}.
+ * @throws IOException In case of any problem.
+ */
+ public static Map<String, String> calculate( byte[] data, List<ChecksumAlgorithmFactory> factories )
+ throws IOException
+ {
+ try ( InputStream inputStream = new ByteArrayInputStream( data ) )
+ {
+ return calculate( inputStream, factories );
+ }
+ }
+
+ /**
+ * Calculates checksums for specified file.
+ *
+ * @param file The file for which to calculate checksums, must not be {@code null}.
+ * @param factories The checksum algorithm factories to use, must not be {@code null}.
+ * @return The calculated checksums, indexed by algorithm name, or the exception that occurred while trying to
+ * calculate it, never {@code null}.
+ * @throws IOException In case of any problem.
+ */
+ public static Map<String, String> calculate( File file, List<ChecksumAlgorithmFactory> factories )
+ throws IOException
+ {
+ try ( InputStream inputStream = new BufferedInputStream( new FileInputStream( file ) ) )
+ {
+ return calculate( inputStream, factories );
+ }
+ }
+
+ private static Map<String, String> calculate( InputStream inputStream, List<ChecksumAlgorithmFactory> factories )
+ throws IOException
+ {
+ LinkedHashMap<String, ChecksumAlgorithm> algorithms = new LinkedHashMap<>();
+ factories.forEach( f -> algorithms.put( f.getName(), f.getAlgorithm() ) );
+ final byte[] buffer = new byte[ 1024 * 32 ];
+ for ( ; ; )
+ {
+ int read = inputStream.read( buffer );
+ if ( read < 0 )
+ {
+ break;
+ }
+ for ( ChecksumAlgorithm checksumAlgorithm : algorithms.values() )
+ {
+ checksumAlgorithm.update( ByteBuffer.wrap( buffer, 0, read ) );
+ }
+ }
+ LinkedHashMap<String, String> result = new LinkedHashMap<>();
+ algorithms.forEach( ( k, v ) -> result.put( k, v.checksum() ) );
+ return result;
+ }
+}
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 eb1716d..f7d7a37 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
@@ -8,9 +8,9 @@ package org.eclipse.aether.spi.connector.checksum;
* 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
@@ -26,7 +26,7 @@ import org.eclipse.aether.transfer.ChecksumFailureException;
* downloaded file, a checksum policy instance is obtained and presented with the available checksums to conclude
* whether the download is valid or not. The following pseudo-code illustrates the usage of a checksum policy by a
* repository connector in some more detail (the retry logic has been omitted for the sake of brevity):
- *
+ *
* <pre>
* void validateChecksums() throws ChecksumFailureException {
* for (checksum : checksums) {
@@ -46,7 +46,7 @@ import org.eclipse.aether.transfer.ChecksumFailureException;
* }
* policy.onNoMoreChecksums();
* }
- *
+ *
* void downloadFile() throws Exception {
* ...
* policy = newChecksumPolicy();
@@ -59,7 +59,7 @@ import org.eclipse.aether.transfer.ChecksumFailureException;
* }
* }
* </pre>
- *
+ * <p>
* Checksum policies might be stateful and are generally not thread-safe.
*/
public interface ChecksumPolicy
@@ -73,12 +73,12 @@ public interface ChecksumPolicy
/**
* 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 bit field providing further details about the checksum. See the {@code KIND_*} constants in
+ * this interface for possible bit flags.
* @return {@code true} to accept the download as valid and stop further validation, {@code false} to continue
- * validation with the next checksum.
+ * validation with the next checksum.
*/
boolean onChecksumMatch( String algorithm, int kind );
@@ -86,39 +86,41 @@ public interface ChecksumPolicy
* Signals a mismatch between the locally computed checksum value and the checksum value declared by the remote
* repository. A simple policy would just rethrow the provided exception. More sophisticated policies could update
* 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 bit field providing further details about the checksum. See the {@code KIND_*} constants in
+ * this
+ * interface for possible bit flags.
* @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.
+ * validation continues with the next checksum.
*/
void onChecksumMismatch( String algorithm, int kind, ChecksumFailureException exception )
- throws ChecksumFailureException;
+ throws ChecksumFailureException;
/**
* Signals an error while computing the local checksum value or retrieving the checksum value from 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 bit field providing further details about the checksum. See the {@code KIND_*} constants in
+ * this
+ * interface for possible bit flags.
* @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.
+ * validation continues with the next checksum.
*/
void onChecksumError( String algorithm, int kind, ChecksumFailureException exception )
- throws ChecksumFailureException;
+ throws ChecksumFailureException;
/**
* Signals that all available checksums have been processed.
- *
+ *
* @throws ChecksumFailureException If the checksum validation is to be failed. If the method returns normally, the
- * download is assumed to be valid.
+ * download is assumed to be valid.
*/
void onNoMoreChecksums()
- throws ChecksumFailureException;
+ throws ChecksumFailureException;
/**
* Signals that the download is being retried after a previously thrown {@link ChecksumFailureException} that is
@@ -130,12 +132,13 @@ public interface ChecksumPolicy
/**
* Signals that (even after a potential retry) checksum validation has failed. A policy could opt to merely log this
* 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 #onNoMoreChecksums()}.
+ * {@link #onChecksumMismatch(String, int, ChecksumFailureException)},
+ * {@link #onChecksumError(String, int, 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.
+ * reject the transferred file as unusable.
*/
boolean onTransferChecksumFailure( ChecksumFailureException exception );
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..8bc88a7 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
@@ -8,9 +8,9 @@ package org.eclipse.aether.spi.connector.layout;
* 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
@@ -21,11 +21,12 @@ package org.eclipse.aether.spi.connector.layout;
import java.net.URI;
import java.util.List;
-import java.util.Locale;
+
import static java.util.Objects.requireNonNull;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
/**
* The layout for a remote repository whose artifacts/metadata can be addressed via URIs.
@@ -36,45 +37,44 @@ public interface RepositoryLayout
{
/**
- * A descriptor for a checksum file. This descriptor simply associates the location of a checksum file with the
- * underlying algorithm used to calculate/verify it. Checksum algorithms are denoted by names as used with
- * {@link java.security.MessageDigest#getInstance(String)}, e.g. {@code "SHA-1"} or {@code "MD5"}.
+ * A descriptor for a checksum location. This descriptor simply associates the location of a checksum file with the
+ * underlying checksum algorithm used to calculate/verify it.
*/
- final class Checksum
+ final class ChecksumLocation
{
-
- private final String algorithm;
-
private final URI location;
+ private final ChecksumAlgorithmFactory checksumAlgorithmFactory;
+
/**
* Creates a new checksum file descriptor with the specified algorithm and location. The method
- * {@link #forLocation(URI, String)} is usually more convenient though.
- *
- * @param algorithm The algorithm used to calculate the checksum, must not be {@code null}.
- * @param location The relative URI to the checksum file within a repository, must not be {@code null}.
+ * {@link #forLocation(URI, ChecksumAlgorithmFactory)} is usually more convenient though.
+ *
+ * @param location The relative URI to the checksum file within a repository, must not be {@code
+ * null}.
+ * @param checksumAlgorithmFactory The checksum type used to calculate the checksum, must not be {@code null}.
*/
- public Checksum( String algorithm, URI location )
+ public ChecksumLocation( URI location, ChecksumAlgorithmFactory checksumAlgorithmFactory )
{
- verify( algorithm, location );
- this.algorithm = algorithm;
+ verify( location, checksumAlgorithmFactory );
this.location = location;
+ this.checksumAlgorithmFactory = checksumAlgorithmFactory;
}
/**
- * Creates a checksum file descriptor for the specified artifact/metadata location and algorithm. The location
+ * Creates a checksum descriptor for the specified artifact/metadata location and algorithm. The location
* of the checksum file itself is derived from the supplied resource URI by appending the file extension
- * corresponding to the algorithm. The file extension in turn is derived from the algorithm name by stripping
- * out any hyphen ('-') characters and lower-casing the name, e.g. "SHA-1" is mapped to ".sha1".
- *
- * @param location The relative URI to the artifact/metadata whose checksum file is being obtained, must not be
- * {@code null} and must not have a query or fragment part.
- * @param algorithm The algorithm used to calculate the checksum, must not be {@code null}.
+ * specified by the algorithm factory. See {@link ChecksumAlgorithmFactory#getFileExtension()}.
+ *
+ * @param location The relative URI to the artifact/metadata whose checksum file is being
+ * obtained, must not be
+ * {@code null} and must not have a query or fragment part.
+ * @param checksumAlgorithmFactory The algorithm used to calculate the checksum, must not be {@code null}.
* @return The checksum file descriptor, never {@code null}.
*/
- public static Checksum forLocation( URI location, String algorithm )
+ public static ChecksumLocation forLocation( URI location, ChecksumAlgorithmFactory checksumAlgorithmFactory )
{
- verify( algorithm, location );
+ verify( location, checksumAlgorithmFactory );
if ( location.getRawQuery() != null )
{
throw new IllegalArgumentException( "resource location must not have query parameters: " + location );
@@ -83,39 +83,34 @@ public interface RepositoryLayout
{
throw new IllegalArgumentException( "resource location must not have a fragment: " + location );
}
- String extension = '.' + algorithm.replace( "-", "" ).toLowerCase( Locale.ENGLISH );
- return new Checksum( algorithm, URI.create( location.toString() + extension ) );
+ return new ChecksumLocation( URI.create( location + "." + checksumAlgorithmFactory.getFileExtension() ),
+ checksumAlgorithmFactory );
}
- private static void verify( String algorithm, URI location )
+ private static void verify( URI location, ChecksumAlgorithmFactory checksumAlgorithmFactory )
{
- requireNonNull( algorithm, "checksum algorithm cannot be null" );
- if ( algorithm.length() == 0 )
- {
- throw new IllegalArgumentException( "checksum algorithm cannot be empty" );
- }
requireNonNull( location, "checksum location cannot be null" );
if ( location.isAbsolute() )
{
throw new IllegalArgumentException( "checksum location must be relative" );
}
+ requireNonNull( checksumAlgorithmFactory, "checksum algorithm factory cannot be null" );
}
/**
- * Gets the name of the algorithm that is used to calculate the checksum.
- *
- * @return The algorithm name, never {@code null}.
- * @see java.security.MessageDigest#getInstance(String)
+ * Gets the {@link ChecksumAlgorithmFactory} that is used to calculate the checksum.
+ *
+ * @return The checksum factory, never {@code null}.
*/
- public String getAlgorithm()
+ public ChecksumAlgorithmFactory getChecksumAlgorithmFactory()
{
- return algorithm;
+ return checksumAlgorithmFactory;
}
/**
* Gets the location of the checksum file with a remote repository. The URI is relative to the root directory of
* the repository.
- *
+ *
* @return The relative URI to the checksum file, never {@code null}.
*/
public URI getLocation()
@@ -126,17 +121,25 @@ public interface RepositoryLayout
@Override
public String toString()
{
- return location + " (" + algorithm + ")";
+ return location + " (" + checksumAlgorithmFactory.getName() + ")";
}
-
}
/**
+ * 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).
+ *
+ * @since 1.8.0
+ */
+ List<String> getChecksumAlgorithmNames();
+
+ /**
* Gets the location within a remote repository where the specified artifact resides. The URI is relative to the
* root directory of the repository.
- *
+ *
* @param artifact The artifact to get the URI for, must not be {@code null}.
- * @param upload {@code false} if the artifact is being downloaded, {@code true} if the artifact is being uploaded.
+ * @param upload {@code false} if the artifact is being downloaded, {@code true} if the artifact is being
+ * uploaded.
* @return The relative URI to the artifact, never {@code null}.
*/
URI getLocation( Artifact artifact, boolean upload );
@@ -144,9 +147,10 @@ public interface RepositoryLayout
/**
* Gets the location within a remote repository where the specified metadata resides. The URI is relative to the
* root directory of the repository.
- *
+ *
* @param metadata The metadata to get the URI for, must not be {@code null}.
- * @param upload {@code false} if the metadata is being downloaded, {@code true} if the metadata is being uploaded.
+ * @param upload {@code false} if the metadata is being downloaded, {@code true} if the metadata is being
+ * uploaded.
* @return The relative URI to the metadata, never {@code null}.
*/
URI getLocation( Metadata metadata, boolean upload );
@@ -154,27 +158,27 @@ public interface RepositoryLayout
/**
* Gets the checksums files that a remote repository keeps to help detect data corruption during transfers of the
* specified artifact.
- *
+ *
* @param artifact The artifact to get the checksum files for, must not be {@code null}.
- * @param upload {@code false} if the checksums are being downloaded/verified, {@code true} if the checksums are
- * being uploaded/created.
+ * @param upload {@code false} if the checksums are being downloaded/verified, {@code true} if the checksums are
+ * being uploaded/created.
* @param location The relative URI to the artifact within the repository as previously obtained from
- * {@link #getLocation(Artifact, boolean)}, must not be {@code null}.
+ * {@link #getLocation(Artifact, boolean)}, must not be {@code null}.
* @return The checksum files for the given artifact, possibly empty but never {@code null}.
*/
- List<Checksum> getChecksums( Artifact artifact, boolean upload, URI location );
+ List<ChecksumLocation> getChecksumLocations( Artifact artifact, boolean upload, URI location );
/**
* Gets the checksums files that a remote repository keeps to help detect data corruption during transfers of the
* specified metadata.
- *
+ *
* @param metadata The metadata to get the checksum files for, must not be {@code null}.
- * @param upload {@code false} if the checksums are being downloaded/verified, {@code true} if the checksums are
- * being uploaded/created.
+ * @param upload {@code false} if the checksums are being downloaded/verified, {@code true} if the checksums are
+ * being uploaded/created.
* @param location The relative URI to the metadata within the repository as previously obtained from
- * {@link #getLocation(Metadata, boolean)}, must not be {@code null}.
+ * {@link #getLocation(Metadata, boolean)}, must not be {@code null}.
* @return The checksum files for the given metadata, possibly empty but never {@code null}.
*/
- List<Checksum> getChecksums( Metadata metadata, boolean upload, URI location );
+ List<ChecksumLocation> getChecksumLocations( Metadata metadata, boolean upload, URI location );
}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/transport/AbstractTransporter.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/transport/AbstractTransporter.java
index 125d84d..45389a6 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/transport/AbstractTransporter.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/transport/AbstractTransporter.java
@@ -22,7 +22,6 @@ package org.eclipse.aether.spi.connector.transport;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -254,14 +253,11 @@ public abstract class AbstractTransporter
private static void copy( OutputStream os, InputStream is, TransportListener listener )
throws IOException, TransferCancelledException
{
- ByteBuffer buffer = ByteBuffer.allocate( 1024 * 32 );
- byte[] array = buffer.array();
- for ( int read = is.read( array ); read >= 0; read = is.read( array ) )
+ byte[] buffer = new byte[ 1024 * 32 ];
+ for ( int read = is.read( buffer ); read >= 0; read = is.read( buffer ) )
{
- os.write( array, 0, read );
- ( (Buffer) buffer ).rewind();
- ( (Buffer) buffer ).limit( read );
- listener.transportProgressed( buffer );
+ os.write( buffer, 0, read );
+ listener.transportProgressed( ByteBuffer.wrap( buffer, 0, read ) );
}
}
diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/io/FileProcessor.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/io/FileProcessor.java
index 9e0f098..0a84eb1 100644
--- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/io/FileProcessor.java
+++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/io/FileProcessor.java
@@ -112,4 +112,20 @@ public interface FileProcessor
}
+ /**
+ * Reads checksum from specified file.
+ *
+ * @throws IOException in case of any IO error.
+ * @since 1.8.0
+ */
+ String readChecksum( File checksumFile ) throws IOException;
+
+ /**
+ * Writes checksum to specified file.
+ *
+ * @throws IOException in case of any IO error.
+ * @since 1.8.0
+ */
+ void writeChecksum( File checksumFile, String checksum ) throws IOException;
+
}
diff --git a/maven-resolver-spi/src/test/java/org/eclipse/aether/spi/connector/layout/ChecksumLocationTest.java b/maven-resolver-spi/src/test/java/org/eclipse/aether/spi/connector/layout/ChecksumLocationTest.java
new file mode 100644
index 0000000..c8b53fa
--- /dev/null
+++ b/maven-resolver-spi/src/test/java/org/eclipse/aether/spi/connector/layout/ChecksumLocationTest.java
@@ -0,0 +1,95 @@
+package org.eclipse.aether.spi.connector.layout;
+
+/*
+ * 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.net.URI;
+
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithm;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
+import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySupport;
+import org.junit.Test;
+
+import org.eclipse.aether.spi.connector.layout.RepositoryLayout.ChecksumLocation;
+
+import static org.junit.Assert.assertEquals;
+
+public class ChecksumLocationTest
+{
+ private ChecksumAlgorithmFactory SHA512 = new ChecksumAlgorithmFactorySupport("SHA-512", "sha512") {
+ @Override
+ public ChecksumAlgorithm getAlgorithm() {
+ throw new RuntimeException("this should not happen");
+ }
+ };
+
+ private ChecksumAlgorithmFactory SHA256 = new ChecksumAlgorithmFactorySupport("SHA-256", "sha256") {
+ @Override
+ public ChecksumAlgorithm getAlgorithm() {
+ throw new RuntimeException("this should not happen");
+ }
+ };
+
+ private ChecksumAlgorithmFactory SHA1 = new ChecksumAlgorithmFactorySupport("SHA-1", "sha1") {
+ @Override
+ public ChecksumAlgorithm getAlgorithm() {
+ throw new RuntimeException("this should not happen");
+ }
+ };
+
+ private ChecksumAlgorithmFactory MD5 = new ChecksumAlgorithmFactorySupport("MD5", "md5") {
+ @Override
+ public ChecksumAlgorithm getAlgorithm() {
+ throw new RuntimeException("this should not happen");
+ }
+ };
+
+ @Test
+ public void testForLocation()
+ {
+ ChecksumLocation cs = ChecksumLocation.forLocation( URI.create( "dir/sub%20dir/file.txt" ), SHA512 );
+ assertEquals( SHA512, cs.getChecksumAlgorithmFactory() );
+ assertEquals( "dir/sub%20dir/file.txt.sha512", cs.getLocation().toString() );
+
+ cs = ChecksumLocation.forLocation( URI.create( "dir/sub%20dir/file.txt" ), SHA256 );
+ assertEquals( SHA256, cs.getChecksumAlgorithmFactory() );
+ assertEquals( "dir/sub%20dir/file.txt.sha256", cs.getLocation().toString() );
+
+ cs = ChecksumLocation.forLocation( URI.create( "dir/sub%20dir/file.txt" ), SHA1 );
+ assertEquals( SHA1, cs.getChecksumAlgorithmFactory() );
+ assertEquals( "dir/sub%20dir/file.txt.sha1", cs.getLocation().toString() );
+
+ cs = ChecksumLocation.forLocation( URI.create( "dir/sub%20dir/file.txt" ), MD5 );
+ assertEquals( MD5, cs.getChecksumAlgorithmFactory() );
+ assertEquals( "dir/sub%20dir/file.txt.md5", cs.getLocation().toString() );
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void testForLocation_WithQueryParams()
+ {
+ ChecksumLocation.forLocation( URI.create( "file.php?param=1" ), SHA1 );
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void testForLocation_WithFragment()
+ {
+ ChecksumLocation.forLocation( URI.create( "file.html#fragment" ), SHA1 );
+ }
+
+}
diff --git a/maven-resolver-spi/src/test/java/org/eclipse/aether/spi/connector/layout/ChecksumTest.java b/maven-resolver-spi/src/test/java/org/eclipse/aether/spi/connector/layout/ChecksumTest.java
deleted file mode 100644
index 4d701b5..0000000
--- a/maven-resolver-spi/src/test/java/org/eclipse/aether/spi/connector/layout/ChecksumTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.eclipse.aether.spi.connector.layout;
-
-/*
- * 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 static org.junit.Assert.*;
-
-import java.net.URI;
-
-import org.junit.Test;
-
-import org.eclipse.aether.spi.connector.layout.RepositoryLayout.Checksum;
-
-public class ChecksumTest
-{
-
- @Test
- public void testForLocation()
- {
- Checksum cs = Checksum.forLocation( URI.create( "dir/sub%20dir/file.txt" ), "SHA-512" );
- assertEquals( "SHA-512", cs.getAlgorithm() );
- assertEquals( "dir/sub%20dir/file.txt.sha512", cs.getLocation().toString() );
-
- cs = Checksum.forLocation( URI.create( "dir/sub%20dir/file.txt" ), "SHA-256" );
- assertEquals( "SHA-256", cs.getAlgorithm() );
- assertEquals( "dir/sub%20dir/file.txt.sha256", cs.getLocation().toString() );
-
- cs = Checksum.forLocation( URI.create( "dir/sub%20dir/file.txt" ), "SHA-1" );
- assertEquals( "SHA-1", cs.getAlgorithm() );
- assertEquals( "dir/sub%20dir/file.txt.sha1", cs.getLocation().toString() );
-
- cs = Checksum.forLocation( URI.create( "dir/sub%20dir/file.txt" ), "MD5" );
- assertEquals( "MD5", cs.getAlgorithm() );
- assertEquals( "dir/sub%20dir/file.txt.md5", cs.getLocation().toString() );
- }
-
- @Test( expected = IllegalArgumentException.class )
- public void testForLocation_WithQueryParams()
- {
- Checksum.forLocation( URI.create( "file.php?param=1" ), "SHA-1" );
- }
-
- @Test( expected = IllegalArgumentException.class )
- public void testForLocation_WithFragment()
- {
- Checksum.forLocation( URI.create( "file.html#fragment" ), "SHA-1" );
- }
-
-}
diff --git a/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestFileProcessor.java b/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestFileProcessor.java
index 00089a7..ae5d9f8 100644
--- a/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestFileProcessor.java
+++ b/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestFileProcessor.java
@@ -29,6 +29,7 @@ import java.io.OutputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import org.eclipse.aether.spi.io.FileProcessor;
@@ -248,4 +249,15 @@ public class TestFileProcessor
}
}
+ @Override
+ public String readChecksum( final File checksumFile ) throws IOException
+ {
+ return new String( Files.readAllBytes( checksumFile.toPath() ), StandardCharsets.UTF_8 );
+ }
+
+ @Override
+ public void writeChecksum( final File checksumFile, final String checksum ) throws IOException
+ {
+ write( checksumFile, checksum );
+ }
}
diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/ChecksumUtils.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/ChecksumUtils.java
index 0ac354f..bf6ed3d 100644
--- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/ChecksumUtils.java
+++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/ChecksumUtils.java
@@ -50,7 +50,9 @@ public final class ChecksumUtils
* @param checksumFile The path to the checksum file, must not be {@code null}.
* @return The checksum stored in the file, never {@code null}.
* @throws IOException If the checksum does not exist or could not be read for other reasons.
+ * @deprecated Use SPI FileProcessor to read and write checksum files.
*/
+ @Deprecated
public static String read( File checksumFile )
throws IOException
{
@@ -101,21 +103,25 @@ public final class ChecksumUtils
* @return The calculated checksums, indexed by algorithm name, or the exception that occurred while trying to
* calculate it, never {@code null}.
* @throws IOException If the data file could not be read.
+ * @deprecated Use SPI checksum selector instead.
*/
+ @Deprecated
public static Map<String, Object> calc( File dataFile, Collection<String> algos )
throws IOException
{
return calc( new FileInputStream( dataFile ), algos );
}
-
+ /**
+ * @deprecated Use SPI checksum selector instead.
+ */
+ @Deprecated
public static Map<String, Object> calc( byte[] dataBytes, Collection<String> algos )
throws IOException
{
return calc( new ByteArrayInputStream( dataBytes ), algos );
}
-
private static Map<String, Object> calc( InputStream data, Collection<String> algos )
throws IOException
{
diff --git a/src/site/markdown/about-checksums.md b/src/site/markdown/about-checksums.md
new file mode 100644
index 0000000..5e55f30
--- /dev/null
+++ b/src/site/markdown/about-checksums.md
@@ -0,0 +1,73 @@
+# About Checksums
+<!--
+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.
+-->
+
+Maven Resolver uses checksums to verify the integrity of downloaded artifacts and
+metadata. Checksums are usually laid out in repositories next to the file in question, with file
+extension telling the checksum algorithm that produced the given checksum file content. Currently,
+most Maven repositories contain SHA-1 and MD5 checksums by default (they are produced by Resolver by default).
+
+Historically, Maven Resolver used `java.security.MessageDigest` to implement checksums. So to say, secure one-way
+hashes provided by Java Cryptography Architecture were (mis)used to implement checksums for transport integrity
+validation. There is no misunderstanding here, secure hashes MAY be used as checksums, as there is quite some
+overlap between checksums and hashes in general. But this simplicity comes at a price: cryptographically safe
+algorithms require way more CPU cycles to calculate checksum, while all their purpose is just
+integrity validation, nothing more. There is no security, trust or whatever else implied or expected from
+them.
+
+If you are interested in trust in your artifacts, it is signatures (for example
+[GPG Signatures](https://maven.apache.org/plugins/maven-gpg-plugin/)) that you should look for.
+
+Hence, the usual argument that "XXX algorithm is unsafe, deprecated, not secure anymore" does not stand in use case
+of Maven Resolver: there is nothing secure being involved with checksums. Moreover, this is true not only for SHA-1
+algorithm, but even for its "elder brother" MD5. Both algorithms are still widely used today as "transport integrity
+validation" or "error detection" (aka "bit-rot detection").
+
+## Checksum Changes
+
+From a technical perspective, the above written facts infer following consequences: as checksum algorithms are exposed
+to the user, so one can set them via configuration, users are not prevented to ask for SHA-256 or even SHA-512, even if
+these algorithms are not part of standard Maven process. Moreover, nothing prevent users (integrating
+Maven Resolver) registering with Java an alternate Java Cryptography Provider and use even broader (or exotic) set
+of message digests for checksums. While this is not wrong or even mistake in any case, we do consider this as
+wrong use case. The notion of transport validation and secure hashes are being constantly mixed up due historical
+reasons explained above.
+
+Hence, Maven Resolver team decided to make supported set of checksums limited. Instead of directly exposing
+`MessageDigest` algorithms, we introduced an API around checksums. This not only prevents wrong use cases (not
+exposing all supported algorithms of `MessageDigest` to users), but also makes possible to introduce real checksum
+algorithms. Finally, the set of supported checksum algorithms remains extensible: if some required algorithm is
+not provided by Resolver, it can be easily added by creating a factory component for it.
+
+Resolver out of the box supports the following checksum algorithms:
+
+* MD5
+* SHA-1
+* SHA-256
+* SHA-512
+
+We are aware that users started using "better SHA" algorithms, and we do not want to break them. Nothing for them
+changes (configuration and everything basically remains the same). But, we do want to prevent any possible further
+proliferation of non-standard checksums.
+
+Links:
+
+* [SHA-1](https://en.wikipedia.org/wiki/SHA-1) (see "Data Integrity" section)
+* [MD5](https://en.wikipedia.org/wiki/MD5) (see "Applications" section, especially about error checking functionality)
+
diff --git a/src/site/markdown/configuration.md b/src/site/markdown/configuration.md
index e5f356e..169f5b0 100644
--- a/src/site/markdown/configuration.md
+++ b/src/site/markdown/configuration.md
@@ -22,7 +22,7 @@ Option | Type | Description | Default Value | Supports Repo ID Suffix
--- | --- | --- | --- | ---
`aether.artifactResolver.snapshotNormalization` | boolean | It replaces the timestamped snapshot file name with a filename containing the `SNAPSHOT` qualifier only. This only affects resolving/retrieving artifacts but not uploading those. | `true` | no
`aether.checksums.forSignature` | boolean | Flag indicating if signature artifacts (`.asc`) should have checksums. | `false` | no
-`aether.checksums.algorithms` | String | List of [algorithms](https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#MessageDigest) passed to [`MessageDigest`](https://docs.oracle.com/javase/7/docs/api/java/security/MessageDigest.html) with which checksums are validated (downloaded) and generated (uploaded). | `"SHA-1,MD5"` | no
+`aether.checksums.algorithms` | String | Comma separated list of checksum algorithms with which checksums are validated (downloaded) and generated (uploaded). Resolver by default supports following algorithms: `MD5`, `SHA-1`, `SHA-256` and `SHA-512`. New algorithms can be added by implementing `ChecksumAlgorithmFactory` component. | `"SHA-1,MD5"` | no
`aether.conflictResolver.verbose` | boolean | Flag controlling the conflict resolver's verbose mode. | `false` | no
`aether.connector.basic.threads` or `maven.artifact.threads` | int | Number of threads to use for uploading/downloading. | `5` | no
`aether.connector.classpath.loader` | ClassLoader | `ClassLoader` from which resources should be retrieved which start with the `classpath:` protocol. | `Thread.currentThread().getContextClassLoader()` | no
diff --git a/src/site/site.xml b/src/site/site.xml
index a18b855..db7af75 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -27,6 +27,7 @@ under the License.
<menu name="Overview">
<item name="Introduction" href="index.html"/>
<item name="Configuration" href="configuration.html"/>
+ <item name="About Checksums" href="about-checksums.html"/>
<item name="Maven 3.8.x" href="maven-3.8.x.html"/>
<item name="JavaDocs" href="apidocs/index.html"/>
<item name="Source Xref" href="xref/index.html"/>