From 7895d55853c13ab3879819bdb8285e514a16a6f3 Mon Sep 17 00:00:00 2001 From: Brett Porter Date: Thu, 10 Aug 2006 12:36:53 +0000 Subject: [PATCH] [MRM-146] support incremental update of checksum Submitted by: Joakim Erdfelt git-svn-id: https://svn.apache.org/repos/asf/maven/repository-manager/trunk@430367 13f79535-47bb-0310-9956-ffa450edef68 --- .../converter/DefaultRepositoryConverter.java | 23 ++- .../converter/RepositoryConverterTest.xml | 16 +- .../discovery/AbstractDiscoverer.java | 1 + .../AbstractArtifactIndexRecordFactory.java | 9 +- .../MinimalArtifactIndexRecordFactory.java | 10 +- .../StandardArtifactIndexRecordFactory.java | 19 +- .../reporting/ChecksumArtifactReporter.java | 19 +- .../reporting/ChecksumMetadataReporter.java | 19 +- .../DuplicateArtifactFileReportProcessor.java | 12 +- ...tractChecksumArtifactReporterTestCase.java | 16 +- .../repository/digest/AbstractDigester.java | 118 +++++++++++++ .../digest/AbstractStreamingDigester.java | 102 +++++++++++ .../repository/digest/DefaultDigester.java | 164 ------------------ .../maven/repository/digest/Digester.java | 28 ++- .../maven/repository/digest/Md5Digester.java | 34 ++++ .../maven/repository/digest/Sha1Digester.java | 34 ++++ .../repository/digest/StreamingDigester.java | 64 +++++++ .../digest/StreamingMd5Digester.java | 35 ++++ .../digest/StreamingSha1Digester.java | 35 ++++ .../maven/repository/digest/DigesterTest.java | 71 +++++--- maven-repository-webapp/pom.xml | 15 +- 21 files changed, 591 insertions(+), 253 deletions(-) create mode 100644 maven-repository-utils/src/main/java/org/apache/maven/repository/digest/AbstractDigester.java create mode 100644 maven-repository-utils/src/main/java/org/apache/maven/repository/digest/AbstractStreamingDigester.java delete mode 100644 maven-repository-utils/src/main/java/org/apache/maven/repository/digest/DefaultDigester.java create mode 100644 maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Md5Digester.java create mode 100644 maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Sha1Digester.java create mode 100644 maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingDigester.java create mode 100644 maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingMd5Digester.java create mode 100644 maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingSha1Digester.java diff --git a/maven-repository-converter/src/main/java/org/apache/maven/repository/converter/DefaultRepositoryConverter.java b/maven-repository-converter/src/main/java/org/apache/maven/repository/converter/DefaultRepositoryConverter.java index 57ee50685..86078ef6b 100644 --- a/maven-repository-converter/src/main/java/org/apache/maven/repository/converter/DefaultRepositoryConverter.java +++ b/maven-repository-converter/src/main/java/org/apache/maven/repository/converter/DefaultRepositoryConverter.java @@ -66,9 +66,14 @@ public class DefaultRepositoryConverter implements RepositoryConverter { /** - * @plexus.requirement + * @plexus.requirement role-hint="sha1" + */ + private Digester sha1Digester; + + /** + * @plexus.requirement role-hint="md5" */ - private Digester digester; + private Digester md5Digester; /** * @plexus.requirement @@ -572,25 +577,25 @@ public class DefaultRepositoryConverter { boolean result = - verifyChecksum( file, file.getName() + ".md5", Digester.MD5, reporter, artifact, "failure.incorrect.md5" ); - result = result && verifyChecksum( file, file.getName() + ".sha1", Digester.SHA1, reporter, artifact, + verifyChecksum( file, file.getName() + ".md5", md5Digester, reporter, artifact, "failure.incorrect.md5" ); + result = result && verifyChecksum( file, file.getName() + ".sha1", sha1Digester, reporter, artifact, "failure.incorrect.sha1" ); return result; } - private boolean verifyChecksum( File file, String fileName, String algorithm, ArtifactReporter reporter, + private boolean verifyChecksum( File file, String fileName, Digester digester, ArtifactReporter reporter, Artifact artifact, String key ) throws IOException { boolean result = true; - File md5 = new File( file.getParentFile(), fileName ); - if ( md5.exists() ) + File checksumFile = new File( file.getParentFile(), fileName ); + if ( checksumFile.exists() ) { - String checksum = FileUtils.fileRead( md5 ); + String checksum = FileUtils.fileRead( checksumFile ); try { - digester.verifyChecksum( file, checksum, algorithm ); + digester.verify( file, checksum ); } catch ( DigesterException e ) { diff --git a/maven-repository-converter/src/test/resources/org/apache/maven/repository/converter/RepositoryConverterTest.xml b/maven-repository-converter/src/test/resources/org/apache/maven/repository/converter/RepositoryConverterTest.xml index e11287cea..f2caaffca 100644 --- a/maven-repository-converter/src/test/resources/org/apache/maven/repository/converter/RepositoryConverterTest.xml +++ b/maven-repository-converter/src/test/resources/org/apache/maven/repository/converter/RepositoryConverterTest.xml @@ -26,7 +26,13 @@ org.apache.maven.repository.digest.Digester - digester + sha1 + sha1Digester + + + org.apache.maven.repository.digest.Digester + md5 + md5Digester org.apache.maven.artifact.factory.ArtifactFactory @@ -52,7 +58,13 @@ org.apache.maven.repository.digest.Digester - digester + sha1 + sha1Digester + + + org.apache.maven.repository.digest.Digester + md5 + md5Digester org.apache.maven.artifact.factory.ArtifactFactory diff --git a/maven-repository-discovery/src/main/java/org/apache/maven/repository/discovery/AbstractDiscoverer.java b/maven-repository-discovery/src/main/java/org/apache/maven/repository/discovery/AbstractDiscoverer.java index b9c721c01..6888b23a9 100644 --- a/maven-repository-discovery/src/main/java/org/apache/maven/repository/discovery/AbstractDiscoverer.java +++ b/maven-repository-discovery/src/main/java/org/apache/maven/repository/discovery/AbstractDiscoverer.java @@ -112,6 +112,7 @@ public abstract class AbstractDiscoverer } scanner.setExcludes( (String[]) allExcludes.toArray( EMPTY_STRING_ARRAY ) ); + // TODO: Correct for extremely large repositories (artifact counts over 200,000 entries) scanner.scan(); for ( Iterator files = Arrays.asList( scanner.getExcludedFiles() ).iterator(); files.hasNext(); ) diff --git a/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/AbstractArtifactIndexRecordFactory.java b/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/AbstractArtifactIndexRecordFactory.java index f077da863..8a9a8cc91 100644 --- a/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/AbstractArtifactIndexRecordFactory.java +++ b/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/AbstractArtifactIndexRecordFactory.java @@ -37,17 +37,12 @@ public abstract class AbstractArtifactIndexRecordFactory extends AbstractLogEnabled implements RepositoryIndexRecordFactory { - /** - * @plexus.requirement - */ - private Digester digester; - - protected String readChecksum( File file, String algorithm ) + protected String readChecksum( File file, Digester digester ) { String checksum; try { - checksum = digester.createChecksum( file, algorithm ).toLowerCase(); + checksum = digester.calc( file ).toLowerCase(); } catch ( DigesterException e ) { diff --git a/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/MinimalArtifactIndexRecordFactory.java b/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/MinimalArtifactIndexRecordFactory.java index dc06bac6f..7f007747c 100644 --- a/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/MinimalArtifactIndexRecordFactory.java +++ b/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/MinimalArtifactIndexRecordFactory.java @@ -40,6 +40,14 @@ public class MinimalArtifactIndexRecordFactory { /* List of types to index. */ private static final Set INDEXED_TYPES = new HashSet( Arrays.asList( new String[]{"jar", "maven-plugin"} ) ); + /** + * @plexus.requirement role-hint="sha1" + */ + protected Digester sha1Digester; + /** + * @plexus.requirement role-hint="md5" + */ + protected Digester md5Digester; public RepositoryIndexRecord createRecord( Artifact artifact ) { @@ -48,7 +56,7 @@ public class MinimalArtifactIndexRecordFactory File file = artifact.getFile(); if ( file != null && INDEXED_TYPES.contains( artifact.getType() ) && file.exists() ) { - String md5 = readChecksum( file, Digester.MD5 ); + String md5 = readChecksum( file, md5Digester ); List files = null; try diff --git a/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/StandardArtifactIndexRecordFactory.java b/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/StandardArtifactIndexRecordFactory.java index 9d6ba7014..ec20288b2 100644 --- a/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/StandardArtifactIndexRecordFactory.java +++ b/maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/StandardArtifactIndexRecordFactory.java @@ -59,7 +59,7 @@ public class StandardArtifactIndexRecordFactory * @todo this should be smarter (perhaps use plexus archiver to look for an unarchiver, and make the ones for zip configurable since sar, par, etc can be added at random. */ private static final Set ARCHIVE_TYPES = - new HashSet( Arrays.asList( new String[]{"jar", "zip", "ejb", "par", "sar", "war", "ear"} ) ); + new HashSet( Arrays.asList( new String[]{"jar", "ejb", "par", "sar", "war", "ear", "rar"} ) ); /** * @plexus.requirement @@ -71,6 +71,16 @@ public class StandardArtifactIndexRecordFactory */ private MavenProjectBuilder projectBuilder; + /** + * @plexus.requirement role-hint="sha1" + */ + protected Digester sha1Digester; + + /** + * @plexus.requirement role-hint="md5" + */ + protected Digester md5Digester; + private static final String PLUGIN_METADATA_NAME = "META-INF/maven/plugin.xml"; private static final String ARCHETYPE_METADATA_NAME = "META-INF/maven/archetype.xml"; @@ -84,12 +94,13 @@ public class StandardArtifactIndexRecordFactory StandardArtifactIndexRecord record = null; File file = artifact.getFile(); + // TODO: is this condition really a possibility? if ( file != null && file.exists() ) { - String md5 = readChecksum( file, Digester.MD5 ); - String sha1 = readChecksum( file, Digester.SHA1 ); - + String md5 = readChecksum( file, md5Digester ); + String sha1 = readChecksum( file, sha1Digester ); + List files = null; boolean archive = ARCHIVE_TYPES.contains( artifact.getType() ); try diff --git a/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/ChecksumArtifactReporter.java b/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/ChecksumArtifactReporter.java index 838045a68..51b4a8772 100644 --- a/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/ChecksumArtifactReporter.java +++ b/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/ChecksumArtifactReporter.java @@ -36,10 +36,15 @@ public class ChecksumArtifactReporter implements ArtifactReportProcessor { /** - * @plexus.requirement + * @plexus.requirement role-hint="sha1" */ - private Digester digester; + private Digester sha1Digester; + /** + * @plexus.requirement role-hint="md5" + */ + private Digester md5Digester; + /** * Validate the checksum of the specified artifact. * @@ -62,11 +67,11 @@ public class ChecksumArtifactReporter String path = repository.pathOf( artifact ); File file = new File( repository.getBasedir(), path ); - verifyChecksum( repository, path + ".md5", file, Digester.MD5, reporter, artifact ); - verifyChecksum( repository, path + ".sha1", file, Digester.SHA1, reporter, artifact ); + verifyChecksum( repository, path + ".md5", file, md5Digester, reporter, artifact ); + verifyChecksum( repository, path + ".sha1", file, sha1Digester, reporter, artifact ); } - private void verifyChecksum( ArtifactRepository repository, String path, File file, String checksumAlgorithm, + private void verifyChecksum( ArtifactRepository repository, String path, File file, Digester digester, ArtifactReporter reporter, Artifact artifact ) { File checksumFile = new File( repository.getBasedir(), path ); @@ -74,7 +79,7 @@ public class ChecksumArtifactReporter { try { - digester.verifyChecksum( file, FileUtils.fileRead( checksumFile ), checksumAlgorithm ); + digester.verify( file, FileUtils.fileRead( checksumFile ) ); reporter.addSuccess( artifact ); } @@ -89,7 +94,7 @@ public class ChecksumArtifactReporter } else { - reporter.addFailure( artifact, checksumAlgorithm + " checksum file does not exist." ); + reporter.addFailure( artifact, digester.getAlgorithm() + " checksum file does not exist." ); } } } diff --git a/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/ChecksumMetadataReporter.java b/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/ChecksumMetadataReporter.java index 885d44d15..df732f656 100644 --- a/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/ChecksumMetadataReporter.java +++ b/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/ChecksumMetadataReporter.java @@ -35,10 +35,15 @@ public class ChecksumMetadataReporter implements MetadataReportProcessor { /** - * @plexus.requirement + * @plexus.requirement role-hint="sha1" */ - private Digester digester; + private Digester sha1Digester; + /** + * @plexus.requirement role-hint="md5" + */ + private Digester md5Digester; + /** * Validate the checksums of the metadata. Get the metadata file from the * repository then validate the checksum. @@ -56,12 +61,12 @@ public class ChecksumMetadataReporter String path = repository.pathOfRemoteRepositoryMetadata( metadata ); File file = new File( repository.getBasedir(), path ); - verifyChecksum( repository, path + ".md5", file, Digester.MD5, reporter, metadata ); - verifyChecksum( repository, path + ".sha1", file, Digester.SHA1, reporter, metadata ); + verifyChecksum( repository, path + ".md5", file, md5Digester, reporter, metadata ); + verifyChecksum( repository, path + ".sha1", file, sha1Digester, reporter, metadata ); } - private void verifyChecksum( ArtifactRepository repository, String path, File file, String checksumAlgorithm, + private void verifyChecksum( ArtifactRepository repository, String path, File file, Digester digester, ArtifactReporter reporter, RepositoryMetadata metadata ) { File checksumFile = new File( repository.getBasedir(), path ); @@ -69,7 +74,7 @@ public class ChecksumMetadataReporter { try { - digester.verifyChecksum( file, FileUtils.fileRead( checksumFile ), checksumAlgorithm ); + digester.verify( file, FileUtils.fileRead( checksumFile ) ); reporter.addSuccess( metadata ); } @@ -84,7 +89,7 @@ public class ChecksumMetadataReporter } else { - reporter.addFailure( metadata, checksumAlgorithm + " checksum file does not exist." ); + reporter.addFailure( metadata, digester.getAlgorithm() + " checksum file does not exist." ); } } diff --git a/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/DuplicateArtifactFileReportProcessor.java b/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/DuplicateArtifactFileReportProcessor.java index 68ead8061..df8c81a85 100644 --- a/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/DuplicateArtifactFileReportProcessor.java +++ b/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/DuplicateArtifactFileReportProcessor.java @@ -16,6 +16,10 @@ package org.apache.maven.repository.reporting; * limitations under the License. */ +import java.io.File; +import java.util.Iterator; +import java.util.List; + import org.apache.lucene.index.Term; import org.apache.lucene.search.TermQuery; import org.apache.maven.artifact.Artifact; @@ -30,10 +34,6 @@ import org.apache.maven.repository.indexing.lucene.LuceneQuery; import org.apache.maven.repository.indexing.record.StandardArtifactIndexRecord; import org.apache.maven.repository.indexing.record.StandardIndexRecordFields; -import java.io.File; -import java.util.Iterator; -import java.util.List; - /** * Validates an artifact file for duplicates within the same groupId based from what's available in a repository index. * @@ -44,7 +44,7 @@ public class DuplicateArtifactFileReportProcessor implements ArtifactReportProcessor { /** - * @plexus.requirement + * @plexus.requirement role-hint="md5" */ private Digester digester; @@ -69,7 +69,7 @@ public class DuplicateArtifactFileReportProcessor String checksum; try { - checksum = digester.createChecksum( artifact.getFile(), Digester.MD5 ); + checksum = digester.calc( artifact.getFile() ); } catch ( DigesterException e ) { diff --git a/maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/AbstractChecksumArtifactReporterTestCase.java b/maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/AbstractChecksumArtifactReporterTestCase.java index 86b60cdca..93b9b2e6e 100644 --- a/maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/AbstractChecksumArtifactReporterTestCase.java +++ b/maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/AbstractChecksumArtifactReporterTestCase.java @@ -45,14 +45,17 @@ public abstract class AbstractChecksumArtifactReporterTestCase private static final String metadataChecksumFilename = "maven-metadata"; - private Digester digester; + private Digester sha1Digest; + + private Digester md5Digest; public void setUp() throws Exception { super.setUp(); - digester = (Digester) lookup( Digester.ROLE ); + sha1Digest = (Digester) lookup( Digester.ROLE, "sha1" ); + md5Digest = (Digester) lookup( Digester.ROLE, "md5" ); } /** @@ -141,7 +144,7 @@ public abstract class AbstractChecksumArtifactReporterTestCase File file = new File( path + ".md5" ); OutputStream os = new FileOutputStream( file ); OutputStreamWriter osw = new OutputStreamWriter( os ); - String sum = digester.createChecksum( new File( path ), Digester.MD5 ); + String sum = md5Digest.calc( new File( path ) ); if ( !isValid ) { osw.write( sum + "1" ); @@ -155,7 +158,7 @@ public abstract class AbstractChecksumArtifactReporterTestCase file = new File( path + ".sha1" ); os = new FileOutputStream( file ); osw = new OutputStreamWriter( os ); - String sha1sum = digester.createChecksum( new File( path ), Digester.SHA1 ); + String sha1sum = sha1Digest.calc( new File( path ) ); if ( !isValid ) { osw.write( sha1sum + "2" ); @@ -187,11 +190,10 @@ public abstract class AbstractChecksumArtifactReporterTestCase FileUtils.copyFile( new File( url ), new File( path ) ); //Create md5 and sha-1 checksum files.. - File file = new File( path + ".md5" ); OutputStream os = new FileOutputStream( file ); OutputStreamWriter osw = new OutputStreamWriter( os ); - String md5sum = digester.createChecksum( new File( path ), Digester.MD5 ); + String md5sum = md5Digest.calc( new File( path ) ); if ( !isValid ) { osw.write( md5sum + "1" ); @@ -205,7 +207,7 @@ public abstract class AbstractChecksumArtifactReporterTestCase file = new File( path + ".sha1" ); os = new FileOutputStream( file ); osw = new OutputStreamWriter( os ); - String sha1sum = digester.createChecksum( new File( path ), Digester.SHA1 ); + String sha1sum = sha1Digest.calc( new File( path ) ); if ( !isValid ) { osw.write( sha1sum + "2" ); diff --git a/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/AbstractDigester.java b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/AbstractDigester.java new file mode 100644 index 000000000..cbc95c0e5 --- /dev/null +++ b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/AbstractDigester.java @@ -0,0 +1,118 @@ +package org.apache.maven.repository.digest; + +/* + * Copyright 2005-2006 The Apache Software Foundation. + * + * Licensed 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.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.StringUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Create a digest for a file. + * + * @author Brett Porter + */ +public abstract class AbstractDigester + implements Digester +{ + private final StreamingDigester streamingDigester; + + protected AbstractDigester( StreamingDigester streamingDigester ) + throws NoSuchAlgorithmException + { + this.streamingDigester = streamingDigester; + } + + public String getAlgorithm() + { + return streamingDigester.getAlgorithm(); + } + + public String calc( File file ) + throws DigesterException + { + FileInputStream fis = null; + try + { + fis = new FileInputStream( file ); + streamingDigester.reset(); + streamingDigester.update( fis ); + return streamingDigester.calc(); + } + catch ( IOException e ) + { + throw new DigesterException( "Unable to calculate the " + streamingDigester.getAlgorithm() + + " hashcode for " + file.getAbsolutePath() + ": " + e.getMessage(), e ); + } + finally + { + IOUtil.close( fis ); + } + } + + public void verify( File file, String checksum ) + throws DigesterException + { + String trimmedChecksum = checksum.replace( '\n', ' ' ).trim(); + + String algorithm = streamingDigester.getAlgorithm(); + + // Free-BSD / openssl + Matcher m = Pattern.compile( algorithm.replaceAll( "-", "" ) + "\\s*\\((.*?)\\)\\s*=\\s*([a-zA-Z0-9]+)" ) + .matcher( trimmedChecksum ); + if ( m.matches() ) + { + String filename = m.group( 1 ); + if ( !filename.equals( file.getName() ) ) + { + throw new DigesterException( "Supplied checksum does not match checksum pattern" ); + } + trimmedChecksum = m.group( 2 ); + } + else + { + // GNU tools + m = Pattern.compile( "([a-zA-Z0-9]+)\\s\\*?(.+)" ).matcher( trimmedChecksum ); + if ( m.matches() ) + { + String filename = m.group( 2 ); + if ( !filename.equals( file.getName() ) ) + { + throw new DigesterException( "Supplied checksum does not match checksum pattern" ); + } + trimmedChecksum = m.group( 1 ); + } + } + + //Create checksum for jar file + String sum = calc( file ); + if ( !StringUtils.equalsIgnoreCase( trimmedChecksum, sum ) ) + { + throw new DigesterException( "Checksum failed" ); + } + } + + public String toString() + { + return "[Digester:" + streamingDigester.getAlgorithm() + "]"; + } +} diff --git a/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/AbstractStreamingDigester.java b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/AbstractStreamingDigester.java new file mode 100644 index 000000000..7d148f657 --- /dev/null +++ b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/AbstractStreamingDigester.java @@ -0,0 +1,102 @@ +package org.apache.maven.repository.digest; + +/* + * Copyright 2005-2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Gradually create a digest for a stream. + * + * @author Brett Porter + */ +public abstract class AbstractStreamingDigester + implements StreamingDigester +{ + protected final MessageDigest md; + + private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray(); + + private static final int HI_MASK = 0xF0; + + private static final int LO_MASK = 0x0F; + + private static final int BUFFER_SIZE = 32768; + + protected AbstractStreamingDigester( String algorithm ) + throws NoSuchAlgorithmException + { + md = MessageDigest.getInstance( algorithm ); + } + + public String getAlgorithm() + { + return md.getAlgorithm(); + } + + public String calc() + throws DigesterException + { + return calc( this.md ); + } + + public void reset() + throws DigesterException + { + md.reset(); + } + + public void update( InputStream is ) + throws DigesterException + { + update( is, md ); + } + + protected static String calc( MessageDigest md ) + { + byte[] digest = md.digest(); + + char[] hash = new char[digest.length * 2]; + for ( int i = 0; i < digest.length; i++ ) + { + hash[i * 2] = HEX_CHARS[( digest[i] & HI_MASK ) >> 4]; + hash[i * 2 + 1] = HEX_CHARS[( digest[i] & LO_MASK )]; + } + return new String( hash ); + } + + protected static void update( InputStream is, MessageDigest digest ) + throws DigesterException + { + try + { + byte[] buffer = new byte[BUFFER_SIZE]; + int size = is.read( buffer, 0, BUFFER_SIZE ); + while ( size >= 0 ) + { + digest.update( buffer, 0, size ); + size = is.read( buffer, 0, BUFFER_SIZE ); + } + } + catch ( IOException e ) + { + throw new DigesterException( "Unable to update " + digest.getAlgorithm() + " hash: " + e.getMessage(), e ); + } + } +} diff --git a/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/DefaultDigester.java b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/DefaultDigester.java deleted file mode 100644 index fc69f9045..000000000 --- a/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/DefaultDigester.java +++ /dev/null @@ -1,164 +0,0 @@ -package org.apache.maven.repository.digest; - -/* - * Copyright 2005-2006 The Apache Software Foundation. - * - * Licensed 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.codehaus.plexus.util.IOUtil; -import org.codehaus.plexus.util.StringUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Create a digest for a file. - * - * @author Brett Porter - * @plexus.component role="org.apache.maven.repository.digest.Digester" - */ -public class DefaultDigester - implements Digester -{ - private static final int CHECKSUM_BUFFER_SIZE = 16384; - - private static final int BYTE_MASK = 0xFF; - - public String createChecksum( File file, String algorithm ) - throws DigesterException - { - MessageDigest digest; - try - { - digest = MessageDigest.getInstance( algorithm ); - } - catch ( NoSuchAlgorithmException e ) - { - throw new DigesterException( "Specified algorithm not found: " + algorithm, e ); - } - - InputStream fis; - try - { - fis = new FileInputStream( file ); - } - catch ( FileNotFoundException e ) - { - throw new DigesterException( "Specified file not found: " + file.getAbsolutePath(), e ); - } - - try - { - byte[] buffer = new byte[CHECKSUM_BUFFER_SIZE]; - int numRead; - do - { - numRead = fis.read( buffer ); - if ( numRead > 0 ) - { - digest.update( buffer, 0, numRead ); - } - } - while ( numRead != -1 ); - } - catch ( IOException e ) - { - throw new DigesterException( "Failed to read from file: " + file.getAbsolutePath(), e ); - } - finally - { - IOUtil.close( fis ); - } - - return byteArrayToHexStr( digest.digest() ); - } - - public void verifyChecksum( File file, String checksum, String algorithm ) - throws DigesterException - { - String trimmedChecksum = checksum.replace( '\n', ' ' ).trim(); - // Free-BSD / openssl - Matcher m = - Pattern.compile( algorithm.replaceAll( "-", "" ) + "\\s*\\((.*?)\\)\\s*=\\s*([a-zA-Z0-9]+)" ).matcher( - trimmedChecksum ); - if ( m.matches() ) - { - String filename = m.group( 1 ); - if ( !filename.equals( file.getName() ) ) - { - throw new DigesterException( "Supplied checksum does not match checksum pattern" ); - } - trimmedChecksum = m.group( 2 ); - } - else - { - // GNU tools - m = Pattern.compile( "([a-zA-Z0-9]+)\\s\\*?(.+)" ).matcher( trimmedChecksum ); - if ( m.matches() ) - { - String filename = m.group( 2 ); - if ( !filename.equals( file.getName() ) ) - { - throw new DigesterException( "Supplied checksum does not match checksum pattern" ); - } - trimmedChecksum = m.group( 1 ); - } - } - - //Create checksum for jar file - String sum = createChecksum( file, algorithm ); - if ( !StringUtils.equalsIgnoreCase( trimmedChecksum, sum ) ) - { - throw new DigesterException( "Checksum failed" ); - } - } - - /** - * Convert an incoming array of bytes into a string that represents each of - * the bytes as two hex characters. - * - * @param data - */ - private static String byteArrayToHexStr( byte[] data ) - { - String output = ""; - - for ( int cnt = 0; cnt < data.length; cnt++ ) - { - //Deposit a byte into the 8 lsb of an int. - int tempInt = data[cnt] & BYTE_MASK; - - //Get hex representation of the int as a string. - String tempStr = Integer.toHexString( tempInt ); - - //Append a leading 0 if necessary so that each hex string will contain 2 characters. - if ( tempStr.length() == 1 ) - { - tempStr = "0" + tempStr; - } - - //Concatenate the two characters to the output string. - output = output + tempStr; - } - - return output.toUpperCase(); - } -} diff --git a/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Digester.java b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Digester.java index ef555bb74..70fb8f6ee 100644 --- a/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Digester.java +++ b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Digester.java @@ -17,6 +17,7 @@ package org.apache.maven.repository.digest; */ import java.io.File; +import java.io.InputStream; /** * Create a digest for a file. @@ -27,13 +28,30 @@ public interface Digester { String ROLE = Digester.class.getName(); - String SHA1 = "SHA-1"; + /** + * Get the algorithm used for the checksum. + * + * @return the algorithm + */ + String getAlgorithm(); - String MD5 = "MD5"; - - String createChecksum( File file, String algorithm ) + /** + * Calculate a checksum for a file. + * + * @param file the file to calculate the checksum for + * @return the current checksum. + * @throws DigesterException if there was a problem computing the hashcode. + */ + String calc( File file ) throws DigesterException; - void verifyChecksum( File file, String checksum, String algorithm ) + /** + * Verify that a checksum is correct. + * + * @param file the file to compute the checksum for + * @param checksum the checksum to compare to + * @throws DigesterException if there was a problem computing the hashcode. + */ + void verify( File file, String checksum ) throws DigesterException; } diff --git a/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Md5Digester.java b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Md5Digester.java new file mode 100644 index 000000000..3ac6a04b2 --- /dev/null +++ b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Md5Digester.java @@ -0,0 +1,34 @@ +package org.apache.maven.repository.digest; + +/* + * Copyright 2005-2006 The Apache Software Foundation. + * + * Licensed 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; + +/** + * Digester that does MD5 Message Digesting Only. + * + * @plexus.component role="org.apache.maven.repository.digest.Digester" role-hint="md5" + */ +public class Md5Digester + extends AbstractDigester +{ + public Md5Digester() + throws NoSuchAlgorithmException + { + super( new StreamingMd5Digester() ); + } +} diff --git a/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Sha1Digester.java b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Sha1Digester.java new file mode 100644 index 000000000..f0383a0c1 --- /dev/null +++ b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Sha1Digester.java @@ -0,0 +1,34 @@ +package org.apache.maven.repository.digest; + +/* + * Copyright 2005-2006 The Apache Software Foundation. + * + * Licensed 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; + +/** + * Digester that does SHA1 Message Digesting Only. + * + * @plexus.component role="org.apache.maven.repository.digest.Digester" role-hint="sha1" + */ +public class Sha1Digester + extends AbstractDigester +{ + public Sha1Digester() + throws NoSuchAlgorithmException + { + super( new StreamingSha1Digester() ); + } +} diff --git a/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingDigester.java b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingDigester.java new file mode 100644 index 000000000..ec0c5a4b7 --- /dev/null +++ b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingDigester.java @@ -0,0 +1,64 @@ +package org.apache.maven.repository.digest; + +/* + * Copyright 2005-2006 The Apache Software Foundation. + * + * Licensed 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.InputStream; + +/** + * Gradually create a digest for a stream. + * + * @author Brett Porter + */ +public interface StreamingDigester +{ + String ROLE = StreamingDigester.class.getName(); + + /** + * Get the algorithm used for the checksum. + * + * @return the algorithm + */ + String getAlgorithm(); + + /** + * Reset the hashcode calculation algorithm. + * Only useful when performing incremental hashcodes based on repeated use of {@link #update(InputStream)} + * + * @throws DigesterException if there was a problem with the internal message digest + */ + void reset() + throws DigesterException; + + /** + * Calculate the current checksum. + * + * @return the current checksum. + * @throws DigesterException if there was a problem computing the hashcode. + */ + String calc() + throws DigesterException; + + /** + * Update the checksum with the content of the input stream. + * + * @param is the input stream + * @throws DigesterException if there was a problem computing the hashcode. + */ + void update( InputStream is ) + throws DigesterException; + +} diff --git a/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingMd5Digester.java b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingMd5Digester.java new file mode 100644 index 000000000..2fc11e45c --- /dev/null +++ b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingMd5Digester.java @@ -0,0 +1,35 @@ +package org.apache.maven.repository.digest; + +/* + * Copyright 2005-2006 The Apache Software Foundation. + * + * Licensed 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; + +/** + * An MD5 implementation of the streaming digester. + * + * @author Brett Porter + * @plexus.component role="org.apache.maven.repository.digest.StreamingDigester" role-hint="md5" + */ +public class StreamingMd5Digester + extends AbstractStreamingDigester +{ + public StreamingMd5Digester() + throws NoSuchAlgorithmException + { + super( "MD5" ); + } +} diff --git a/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingSha1Digester.java b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingSha1Digester.java new file mode 100644 index 000000000..845989eca --- /dev/null +++ b/maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingSha1Digester.java @@ -0,0 +1,35 @@ +package org.apache.maven.repository.digest; + +/* + * Copyright 2005-2006 The Apache Software Foundation. + * + * Licensed 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; + +/** + * An SHA-1 implementation of the streaming digester. + * + * @author Brett Porter + * @plexus.component role="org.apache.maven.repository.digest.StreamingDigester" role-hint="sha1" + */ +public class StreamingSha1Digester + extends AbstractStreamingDigester +{ + public StreamingSha1Digester() + throws NoSuchAlgorithmException + { + super( "SHA-1" ); + } +} diff --git a/maven-repository-utils/src/test/java/org/apache/maven/repository/digest/DigesterTest.java b/maven-repository-utils/src/test/java/org/apache/maven/repository/digest/DigesterTest.java index 31a47376c..97477d142 100644 --- a/maven-repository-utils/src/test/java/org/apache/maven/repository/digest/DigesterTest.java +++ b/maven-repository-utils/src/test/java/org/apache/maven/repository/digest/DigesterTest.java @@ -16,7 +16,7 @@ package org.apache.maven.repository.digest; * limitations under the License. */ -import junit.framework.TestCase; +import org.codehaus.plexus.PlexusTestCase; import java.io.File; import java.io.IOException; @@ -28,16 +28,33 @@ import java.security.NoSuchAlgorithmException; * @author Brett Porter */ public class DigesterTest - extends TestCase + extends PlexusTestCase { - private Digester digester = new DefaultDigester(); - private static final String MD5 = "adbc688ce77fa2aece4bb72cad9f98ba"; private static final String SHA1 = "2a7b459938e12a2dc35d1bf6cff35e9c2b592fa9"; private static final String WRONG_SHA1 = "4d8703779816556cdb8be7f6bb5c954f4b5730e2"; + private Digester sha1Digest; + + private Digester md5Digest; + + protected void setUp() + throws Exception + { + super.setUp(); + + sha1Digest = (Digester) lookup( Digester.ROLE, "sha1" ); + md5Digest = (Digester) lookup( Digester.ROLE, "md5" ); + } + + public void testAlgorithm() + { + assertEquals( "SHA-1", sha1Digest.getAlgorithm() ); + assertEquals( "MD5", md5Digest.getAlgorithm() ); + } + public void testBareDigestFormat() throws DigesterException, IOException { @@ -45,7 +62,7 @@ public class DigesterTest try { - digester.verifyChecksum( file, MD5, Digester.MD5 ); + md5Digest.verify( file, MD5 ); } catch ( DigesterException e ) { @@ -54,7 +71,7 @@ public class DigesterTest try { - digester.verifyChecksum( file, SHA1, Digester.SHA1 ); + sha1Digest.verify( file, SHA1 ); } catch ( DigesterException e ) { @@ -63,7 +80,7 @@ public class DigesterTest try { - digester.verifyChecksum( file, WRONG_SHA1, Digester.SHA1 ); + sha1Digest.verify( file, WRONG_SHA1 ); fail( "wrong checksum must throw an exception" ); } catch ( DigesterException e ) @@ -73,12 +90,13 @@ public class DigesterTest } public void testOpensslDigestFormat() - throws IOException + throws IOException, DigesterException { File file = new File( getClass().getResource( "/test-file.txt" ).getPath() ); + try { - digester.verifyChecksum( file, "MD5(test-file.txt)= " + MD5, Digester.MD5 ); + md5Digest.verify( file, "MD5(test-file.txt)= " + MD5 ); } catch ( DigesterException e ) { @@ -87,25 +105,25 @@ public class DigesterTest try { - digester.verifyChecksum( file, "SHA1(test-file.txt)= " + SHA1, Digester.SHA1 ); + md5Digest.verify( file, "MD5 (test-file.txt) = " + MD5 ); } catch ( DigesterException e ) { - fail( "OpenSSL SHA1 format must not cause exception" ); + fail( "FreeBSD MD5 format must not cause exception" ); } try { - digester.verifyChecksum( file, "MD5 (test-file.txt) = " + MD5, Digester.MD5 ); + sha1Digest.verify( file, "SHA1(test-file.txt)= " + SHA1 ); } catch ( DigesterException e ) { - fail( "FreeBSD MD5 format must not cause exception" ); + fail( "OpenSSL SHA1 format must not cause exception" ); } try { - digester.verifyChecksum( file, "SHA1 (test-file.txt) = " + SHA1, Digester.SHA1 ); + sha1Digest.verify( file, "SHA1 (test-file.txt) = " + SHA1 ); } catch ( DigesterException e ) { @@ -114,7 +132,7 @@ public class DigesterTest try { - digester.verifyChecksum( file, "SHA1 (FOO) = " + SHA1, Digester.SHA1 ); + sha1Digest.verify( file, "SHA1 (FOO) = " + SHA1 ); fail( "Wrong filename should cause an exception" ); } catch ( DigesterException e ) @@ -124,7 +142,7 @@ public class DigesterTest try { - digester.verifyChecksum( file, "SHA1 (test-file.txt) = " + WRONG_SHA1, Digester.SHA1 ); + sha1Digest.verify( file, "SHA1 (test-file.txt) = " + WRONG_SHA1 ); fail( "Wrong sha1 should cause an exception" ); } catch ( DigesterException e ) @@ -134,12 +152,13 @@ public class DigesterTest } public void testGnuDigestFormat() - throws NoSuchAlgorithmException, IOException + throws NoSuchAlgorithmException, IOException, DigesterException { File file = new File( getClass().getResource( "/test-file.txt" ).getPath() ); + try { - digester.verifyChecksum( file, MD5 + " *test-file.txt", Digester.MD5 ); + md5Digest.verify( file, MD5 + " *test-file.txt" ); } catch ( DigesterException e ) { @@ -148,25 +167,25 @@ public class DigesterTest try { - digester.verifyChecksum( file, SHA1 + " *test-file.txt", Digester.SHA1 ); + md5Digest.verify( file, MD5 + " test-file.txt" ); } catch ( DigesterException e ) { - fail( "GNU format SHA1 must not cause exception" ); + fail( "GNU text format MD5 must not cause exception" ); } try { - digester.verifyChecksum( file, MD5 + " test-file.txt", Digester.MD5 ); + sha1Digest.verify( file, SHA1 + " *test-file.txt" ); } catch ( DigesterException e ) { - fail( "GNU text format MD5 must not cause exception" ); + fail( "GNU format SHA1 must not cause exception" ); } try { - digester.verifyChecksum( file, SHA1 + " test-file.txt", Digester.SHA1 ); + sha1Digest.verify( file, SHA1 + " test-file.txt" ); } catch ( DigesterException e ) { @@ -175,7 +194,7 @@ public class DigesterTest try { - digester.verifyChecksum( file, SHA1 + " FOO", Digester.SHA1 ); + sha1Digest.verify( file, SHA1 + " FOO" ); fail( "Wrong filename cause an exception" ); } catch ( DigesterException e ) @@ -185,7 +204,7 @@ public class DigesterTest try { - digester.verifyChecksum( file, WRONG_SHA1 + " test-file.txt", Digester.SHA1 ); + sha1Digest.verify( file, WRONG_SHA1 + " test-file.txt" ); fail( "Wrong SHA1 cause an exception" ); } catch ( DigesterException e ) @@ -200,7 +219,7 @@ public class DigesterTest File file = new File( getClass().getResource( "/test-file.txt" ).getPath() ); try { - digester.verifyChecksum( file, SHA1 + " *test-file.txt \n", Digester.SHA1 ); + sha1Digest.verify( file, SHA1 + " *test-file.txt \n" ); } catch ( DigesterException e ) { diff --git a/maven-repository-webapp/pom.xml b/maven-repository-webapp/pom.xml index 074f3be4d..311d636a1 100644 --- a/maven-repository-webapp/pom.xml +++ b/maven-repository-webapp/pom.xml @@ -151,14 +151,13 @@ org.codehaus.mojo cobertura-maven-plugin - - - - - **/** - - - + + + + clean + + + org.codehaus.plexus -- 2.39.5