You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by cs...@apache.org on 2021/12/14 14:26:06 UTC
[maven-resolver] 01/01: Checksum is not a digest
This is an automated email from the ASF dual-hosted git repository.
cstamas pushed a commit to branch checksums
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit ede442ff75f4da8c7797d87529086307146f9e5b
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Tue Dec 14 15:25:09 2021 +0100
Checksum is not a digest
Distance ourselves from MessageDigest, and open up ways
to define and support different (real) checksum implementations
as well.
---
.../connector/basic/BasicRepositoryConnector.java | 17 +++--
.../basic/BasicRepositoryConnectorFactory.java | 23 +++++-
.../aether/connector/basic/ChecksumCalculator.java | 59 +++++++++------
.../connector/basic/ChecksumImplementation.java | 41 ++++++++++
.../basic/ChecksumImplementationSelector.java | 37 +++++++++
.../aether/connector/basic/ChecksumValidator.java | 14 +++-
.../DefaultChecksumImplementationSelector.java | 87 ++++++++++++++++++++++
.../FooChecksumImplementationProvider.java | 62 +++++++++++++++
.../connector/basic/ChecksumCalculatorTest.java | 4 +-
.../connector/basic/ChecksumValidatorTest.java | 4 +-
10 files changed, 311 insertions(+), 37 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..76a6097 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
@@ -99,6 +99,8 @@ final class BasicRepositoryConnector
private final ChecksumPolicyProvider checksumPolicyProvider;
+ private final ChecksumImplementationSelector checksumImplementationSelector;
+
private final PartialFile.Factory partialFileFactory;
private final int maxThreads;
@@ -111,9 +113,13 @@ final class BasicRepositoryConnector
private boolean closed;
- BasicRepositoryConnector( RepositorySystemSession session, RemoteRepository repository,
- TransporterProvider transporterProvider, RepositoryLayoutProvider layoutProvider,
- ChecksumPolicyProvider checksumPolicyProvider, FileProcessor fileProcessor )
+ BasicRepositoryConnector( RepositorySystemSession session,
+ RemoteRepository repository,
+ TransporterProvider transporterProvider,
+ RepositoryLayoutProvider layoutProvider,
+ ChecksumPolicyProvider checksumPolicyProvider,
+ ChecksumImplementationSelector checksumImplementationSelector,
+ FileProcessor fileProcessor )
throws NoRepositoryConnectorException
{
try
@@ -133,6 +139,7 @@ final class BasicRepositoryConnector
throw new NoRepositoryConnectorException( repository, e.getMessage(), e );
}
this.checksumPolicyProvider = checksumPolicyProvider;
+ this.checksumImplementationSelector = checksumImplementationSelector;
this.session = session;
this.repository = repository;
@@ -406,8 +413,8 @@ final class BasicRepositoryConnector
{
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( checksums ), checksumImplementationSelector );
}
public void checkRemoteAccess()
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java
index aa747a9..a4ed966 100644
--- a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory.java
@@ -51,6 +51,8 @@ public final class BasicRepositoryConnectorFactory
private ChecksumPolicyProvider checksumPolicyProvider;
+ private ChecksumImplementationSelector checksumImplementationSelector;
+
private FileProcessor fileProcessor;
private float priority;
@@ -67,11 +69,14 @@ public final class BasicRepositoryConnectorFactory
@Inject
BasicRepositoryConnectorFactory( TransporterProvider transporterProvider, RepositoryLayoutProvider layoutProvider,
- ChecksumPolicyProvider checksumPolicyProvider, FileProcessor fileProcessor )
+ ChecksumPolicyProvider checksumPolicyProvider,
+ ChecksumImplementationSelector checksumImplementationSelector,
+ FileProcessor fileProcessor )
{
setTransporterProvider( transporterProvider );
setRepositoryLayoutProvider( layoutProvider );
setChecksumPolicyProvider( checksumPolicyProvider );
+ setChecksumImplementationSelector( checksumImplementationSelector );
setFileProcessor( fileProcessor );
}
@@ -121,6 +126,20 @@ public final class BasicRepositoryConnectorFactory
}
/**
+ * Sets the checksum implementation selector to use for this component.
+ *
+ * @param checksumImplementationSelector The checksum implementation selector to use, must not be {@code null}.
+ * @return This component for chaining, never {@code null}.
+ */
+ public BasicRepositoryConnectorFactory setChecksumImplementationSelector(
+ ChecksumImplementationSelector checksumImplementationSelector )
+ {
+ this.checksumImplementationSelector = requireNonNull(
+ checksumImplementationSelector, "checksum implementation selector cannot be null" );
+ return this;
+ }
+
+ /**
* Sets the file processor to use for this component.
*
* @param fileProcessor The file processor to use, must not be {@code null}.
@@ -156,7 +175,7 @@ public final class BasicRepositoryConnectorFactory
requireNonNull( "repository", "repository cannot be null" );
return new BasicRepositoryConnector( session, repository, transporterProvider, layoutProvider,
- checksumPolicyProvider, fileProcessor );
+ checksumPolicyProvider, checksumImplementationSelector, fileProcessor );
}
}
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..ffe7865 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
@@ -25,7 +25,6 @@ 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;
@@ -38,6 +37,8 @@ import java.util.Set;
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.
*/
@@ -48,45 +49,44 @@ final class ChecksumCalculator
{
final String algorithm;
- final MessageDigest digest;
+ final ChecksumImplementation engine;
Exception error;
- Checksum( String algorithm )
+ Checksum( String algorithm, ChecksumImplementation engine )
{
- this.algorithm = algorithm;
- MessageDigest digest = null;
- try
- {
- digest = MessageDigest.getInstance( algorithm );
- }
- catch ( NoSuchAlgorithmException e )
- {
- error = e;
- }
- this.digest = digest;
+ this.algorithm = requireNonNull( algorithm );
+ this.engine = requireNonNull( engine );
+
+ }
+
+ Checksum( String algorithm, Exception error )
+ {
+ this.algorithm = requireNonNull( algorithm );
+ this.engine = null;
+ this.error = requireNonNull( error );
}
public void update( ByteBuffer buffer )
{
- if ( digest != null )
+ if ( engine != null )
{
- digest.update( buffer );
+ engine.update( buffer );
}
}
public void reset()
{
- if ( digest != null )
+ if ( engine != null )
{
- digest.reset();
+ engine.reset();
error = null;
}
}
public void error( Exception error )
{
- if ( digest != null )
+ if ( engine != null )
{
this.error = error;
}
@@ -98,7 +98,7 @@ final class ChecksumCalculator
{
return error;
}
- return ChecksumUtils.toHexString( digest.digest() );
+ return ChecksumUtils.toHexString( engine.digest() );
}
}
@@ -107,16 +107,20 @@ final class ChecksumCalculator
private final File targetFile;
- public static ChecksumCalculator newInstance( File targetFile, Collection<RepositoryLayout.Checksum> checksums )
+ public static ChecksumCalculator newInstance( ChecksumImplementationSelector selector,
+ File targetFile,
+ Collection<RepositoryLayout.Checksum> checksums )
{
if ( checksums == null || checksums.isEmpty() )
{
return null;
}
- return new ChecksumCalculator( targetFile, checksums );
+ return new ChecksumCalculator( selector, targetFile, checksums );
}
- private ChecksumCalculator( File targetFile, Collection<RepositoryLayout.Checksum> checksums )
+ private ChecksumCalculator( ChecksumImplementationSelector selector,
+ File targetFile,
+ Collection<RepositoryLayout.Checksum> checksums )
{
this.checksums = new ArrayList<>();
Set<String> algos = new HashSet<>();
@@ -125,7 +129,14 @@ final class ChecksumCalculator
String algo = checksum.getAlgorithm();
if ( algos.add( algo ) )
{
- this.checksums.add( new Checksum( algo ) );
+ try
+ {
+ this.checksums.add( new Checksum( algo, selector.select( algo ) ) );
+ }
+ catch ( NoSuchAlgorithmException e )
+ {
+ this.checksums.add( new Checksum( algo, e ) );
+ }
}
}
this.targetFile = targetFile;
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumImplementation.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumImplementation.java
new file mode 100644
index 0000000..02cdc36
--- /dev/null
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumImplementation.java
@@ -0,0 +1,41 @@
+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;
+
+/**
+ * Implementation performing checksum calculation for specific algorithm. Instances of this interface as stateful,
+ * should be reused only after {@link #reset()}.
+ *
+ * <strong>Important note:</strong> if implementation of this interface is component, it MUST NOT be singleton, but
+ * must adhere to "prototype" pattern. Alternative is just to implement a provider, and on each get invocation create
+ * new instance.
+ *
+ * @since TBD
+ */
+public interface ChecksumImplementation
+{
+ void update( ByteBuffer input );
+
+ void reset();
+
+ byte[] digest();
+}
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumImplementationSelector.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumImplementationSelector.java
new file mode 100644
index 0000000..b4169b1
--- /dev/null
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumImplementationSelector.java
@@ -0,0 +1,37 @@
+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.security.NoSuchAlgorithmException;
+
+/**
+ * Selector that selects implemntation based on passed in algorithm name.
+ *
+ * @since TBD
+ */
+public interface ChecksumImplementationSelector
+{
+ /**
+ * Returns a new instance ready to perform checksum calculation for given algorithm, never {@code null}.
+ *
+ * @throws NoSuchAlgorithmException if algorithm asked for is not supported.
+ */
+ ChecksumImplementation select( String algorithm ) throws NoSuchAlgorithmException;
+}
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..31b2df2 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
@@ -65,11 +65,16 @@ final class ChecksumValidator
private final Collection<Checksum> checksums;
+ private final ChecksumImplementationSelector checksumImplementationSelector;
+
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<Checksum> checksums,
+ ChecksumImplementationSelector checksumImplementationSelector )
{
this.dataFile = dataFile;
this.tempFiles = new HashSet<>();
@@ -77,6 +82,7 @@ final class ChecksumValidator
this.checksumFetcher = checksumFetcher;
this.checksumPolicy = checksumPolicy;
this.checksums = checksums;
+ this.checksumImplementationSelector = checksumImplementationSelector;
checksumFiles = new HashMap<>();
}
@@ -84,7 +90,7 @@ final class ChecksumValidator
{
if ( checksumPolicy != null )
{
- return ChecksumCalculator.newInstance( targetFile, checksums );
+ return ChecksumCalculator.newInstance( checksumImplementationSelector, targetFile, checksums );
}
return null;
}
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/checksum/DefaultChecksumImplementationSelector.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/checksum/DefaultChecksumImplementationSelector.java
new file mode 100644
index 0000000..84422cd
--- /dev/null
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/checksum/DefaultChecksumImplementationSelector.java
@@ -0,0 +1,87 @@
+package org.eclipse.aether.connector.basic.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;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.eclipse.aether.connector.basic.ChecksumImplementation;
+import org.eclipse.aether.connector.basic.ChecksumImplementationSelector;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Default implementation of {@link ChecksumImplementationSelector}.
+ */
+@Singleton
+@Named
+public class DefaultChecksumImplementationSelector
+ implements ChecksumImplementationSelector
+{
+ private final Map<String, Provider<ChecksumImplementation>> providers;
+
+ @Inject
+ public DefaultChecksumImplementationSelector( final Map<String, Provider<ChecksumImplementation>> providers )
+ {
+ this.providers = requireNonNull( providers );
+ }
+
+ @Override
+ public ChecksumImplementation select( final String algorithm ) throws NoSuchAlgorithmException
+ {
+ requireNonNull( algorithm, "algorithm name must not be null" );
+ Provider<ChecksumImplementation> provider = providers.get( algorithm.toUpperCase( Locale.ENGLISH ) );
+ if ( provider != null )
+ {
+ return provider.get();
+ }
+
+ // fallback to MessageDigest backed one
+ MessageDigest messageDigest = MessageDigest.getInstance( algorithm );
+ return new ChecksumImplementation()
+ {
+ @Override
+ public void update( final ByteBuffer input )
+ {
+ messageDigest.update( input );
+ }
+
+ @Override
+ public void reset()
+ {
+ messageDigest.reset();
+ }
+
+ @Override
+ public byte[] digest()
+ {
+ return messageDigest.digest();
+ }
+ };
+ }
+}
diff --git a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/checksum/FooChecksumImplementationProvider.java b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/checksum/FooChecksumImplementationProvider.java
new file mode 100644
index 0000000..1ccf178
--- /dev/null
+++ b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/checksum/FooChecksumImplementationProvider.java
@@ -0,0 +1,62 @@
+package org.eclipse.aether.connector.basic.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;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.eclipse.aether.connector.basic.ChecksumImplementation;
+
+/**
+ * Provides FOO calculating checksum implementation.
+ *
+ * @since TBD
+ */
+@Singleton
+@Named( "FOO" )
+public class FooChecksumImplementationProvider
+ implements Provider<ChecksumImplementation>
+{
+ @Override
+ public ChecksumImplementation get()
+ {
+ return new ChecksumImplementation()
+ {
+ @Override
+ public void update( final ByteBuffer input )
+ {
+ }
+
+ @Override
+ public void reset()
+ {
+ }
+
+ @Override
+ public byte[] digest()
+ {
+ return new byte[] { 0x1, 0x2 };
+ }
+ };
+ }
+}
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..27a1373 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
@@ -28,9 +28,11 @@ import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
+import org.eclipse.aether.connector.basic.checksum.DefaultChecksumImplementationSelector;
import org.eclipse.aether.internal.test.util.TestFileUtils;
import org.eclipse.aether.spi.connector.layout.RepositoryLayout;
import org.junit.Before;
@@ -56,7 +58,7 @@ public class ChecksumCalculatorTest
{
checksums.add( new RepositoryLayout.Checksum( algo, URI.create( "irrelevant" ) ) );
}
- return ChecksumCalculator.newInstance( file, checksums );
+ return ChecksumCalculator.newInstance( new DefaultChecksumImplementationSelector( Collections.emptyMap() ), file, checksums );
}
private ByteBuffer toBuffer( String data )
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..8950aee 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
@@ -26,11 +26,13 @@ import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import org.eclipse.aether.connector.basic.checksum.DefaultChecksumImplementationSelector;
import org.eclipse.aether.internal.test.util.TestFileProcessor;
import org.eclipse.aether.internal.test.util.TestFileUtils;
import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy;
@@ -194,7 +196,7 @@ public class ChecksumValidatorTest
private ChecksumValidator newValidator( String... algos )
{
- return new ChecksumValidator( dataFile, new TestFileProcessor(), fetcher, policy, newChecksums( algos ) );
+ return new ChecksumValidator( dataFile, new TestFileProcessor(), fetcher, policy, newChecksums( algos ), new DefaultChecksumImplementationSelector( Collections.emptyMap() ));
}
private Map<String, ?> checksums( String... algoDigestPairs )