]> source.dussan.org Git - archiva.git/commitdiff
[MRM-146] support incremental update of checksum
authorBrett Porter <brett@apache.org>
Thu, 10 Aug 2006 12:36:53 +0000 (12:36 +0000)
committerBrett Porter <brett@apache.org>
Thu, 10 Aug 2006 12:36:53 +0000 (12:36 +0000)
Submitted by: Joakim Erdfelt

git-svn-id: https://svn.apache.org/repos/asf/maven/repository-manager/trunk@430367 13f79535-47bb-0310-9956-ffa450edef68

21 files changed:
maven-repository-converter/src/main/java/org/apache/maven/repository/converter/DefaultRepositoryConverter.java
maven-repository-converter/src/test/resources/org/apache/maven/repository/converter/RepositoryConverterTest.xml
maven-repository-discovery/src/main/java/org/apache/maven/repository/discovery/AbstractDiscoverer.java
maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/AbstractArtifactIndexRecordFactory.java
maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/MinimalArtifactIndexRecordFactory.java
maven-repository-indexer/src/main/java/org/apache/maven/repository/indexing/record/StandardArtifactIndexRecordFactory.java
maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/ChecksumArtifactReporter.java
maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/ChecksumMetadataReporter.java
maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/DuplicateArtifactFileReportProcessor.java
maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/AbstractChecksumArtifactReporterTestCase.java
maven-repository-utils/src/main/java/org/apache/maven/repository/digest/AbstractDigester.java [new file with mode: 0644]
maven-repository-utils/src/main/java/org/apache/maven/repository/digest/AbstractStreamingDigester.java [new file with mode: 0644]
maven-repository-utils/src/main/java/org/apache/maven/repository/digest/DefaultDigester.java [deleted file]
maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Digester.java
maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Md5Digester.java [new file with mode: 0644]
maven-repository-utils/src/main/java/org/apache/maven/repository/digest/Sha1Digester.java [new file with mode: 0644]
maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingDigester.java [new file with mode: 0644]
maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingMd5Digester.java [new file with mode: 0644]
maven-repository-utils/src/main/java/org/apache/maven/repository/digest/StreamingSha1Digester.java [new file with mode: 0644]
maven-repository-utils/src/test/java/org/apache/maven/repository/digest/DigesterTest.java
maven-repository-webapp/pom.xml

index 57ee506857b2b83c8e085384dd9f9437192cb6e5..86078ef6ba1701b428a8eabcb1538cf80826f844 100644 (file)
@@ -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 )
             {
index e11287cea3b99c49098410640659d84250932311..f2caaffca5072289768a97eda857ee8222290d5e 100644 (file)
       <requirements>
         <requirement>
           <role>org.apache.maven.repository.digest.Digester</role>
-          <field-name>digester</field-name>
+          <role-hint>sha1</role-hint>
+          <field-name>sha1Digester</field-name>
+        </requirement>
+        <requirement>
+          <role>org.apache.maven.repository.digest.Digester</role>
+          <role-hint>md5</role-hint>
+          <field-name>md5Digester</field-name>
         </requirement>
         <requirement>
           <role>org.apache.maven.artifact.factory.ArtifactFactory</role>
       <requirements>
         <requirement>
           <role>org.apache.maven.repository.digest.Digester</role>
-          <field-name>digester</field-name>
+          <role-hint>sha1</role-hint>
+          <field-name>sha1Digester</field-name>
+        </requirement>
+        <requirement>
+          <role>org.apache.maven.repository.digest.Digester</role>
+          <role-hint>md5</role-hint>
+          <field-name>md5Digester</field-name>
         </requirement>
         <requirement>
           <role>org.apache.maven.artifact.factory.ArtifactFactory</role>
index b9c721c01ad8f6d0f1339c16f5f791be2c81fbf8..6888b23a9d51bf017560410cdd3386886b1692c0 100644 (file)
@@ -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(); )
index f077da863cf2bcaf5135260607db763ca5a0e3ae..8a9a8cc9194271ae1b0399b2147b1ec429048fa8 100644 (file)
@@ -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 )
         {
index dc06bac6fbe386fb40da490eb05d9d1ac904871c..7f007747c96b3d4abf6cdf86d63d868e96475ac6 100644 (file)
@@ -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
index 9d6ba7014331fffa92e264874a2caa81a9120f8a..ec20288b2a3062e8ecd52ad6ac6180fd92da4825 100644 (file)
@@ -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
index 838045a6891bb942fce65c5db72b543e8c8cced1..51b4a877247a6f44c3c3f874c5b78baab66c5e03 100644 (file)
@@ -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." );
         }
     }
 }
index 885d44d15b05a6ec7aae8a5ece0b9abd66e357fe..df732f656433d7552e6599bd5628f6692b06e0ba 100644 (file)
@@ -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." );
         }
     }
 
index 68ead806116fe723d368bfc6aec25bf8febdd048..df8c81a85fcfb1f4825a9163facda9c3c3f3c1b1 100644 (file)
@@ -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 )
             {
index 86b60cdca1a90d68f11cd4ad8f637b330fd89116..93b9b2e6e99d50c3b8efff895fd8be6a46ed12d3 100644 (file)
@@ -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 (file)
index 0000000..cbc95c0
--- /dev/null
@@ -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 <a href="mailto:brett@apache.org">Brett Porter</a>
+ */
+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 (file)
index 0000000..7d148f6
--- /dev/null
@@ -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 <a href="mailto:brett@apache.org">Brett Porter</a>
+ */
+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 (file)
index fc69f90..0000000
+++ /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 <a href="mailto:brett@apache.org">Brett Porter</a>
- * @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();
-    }
-}
index ef555bb7421737cf279c29fa633471799c03bf82..70fb8f6ee3f317c49c748928cdc01767eecb2562 100644 (file)
@@ -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 (file)
index 0000000..3ac6a04
--- /dev/null
@@ -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 (file)
index 0000000..f0383a0
--- /dev/null
@@ -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 (file)
index 0000000..ec0c5a4
--- /dev/null
@@ -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 <a href="mailto:brett@apache.org">Brett Porter</a>
+ */
+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 (file)
index 0000000..2fc11e4
--- /dev/null
@@ -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 <a href="mailto:brett@apache.org">Brett Porter</a>
+ * @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 (file)
index 0000000..845989e
--- /dev/null
@@ -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 <a href="mailto:brett@apache.org">Brett Porter</a>
+ * @plexus.component role="org.apache.maven.repository.digest.StreamingDigester" role-hint="sha1"
+ */
+public class StreamingSha1Digester
+    extends AbstractStreamingDigester
+{
+    public StreamingSha1Digester()
+        throws NoSuchAlgorithmException
+    {
+        super( "SHA-1" );
+    }
+}
index 31a47376ca41c01ae25899ec07247fef555cbe55..97477d1426159d21f3d2a5d42125ee1c2b0ef46a 100644 (file)
@@ -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 <a href="mailto:brett@apache.org">Brett Porter</a>
  */
 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 )
         {
index 074f3be4d19072f57e30af97373cc534dd5e6a1b..311d636a17e89aa5723441a45dab98546f4a6c38 100644 (file)
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>cobertura-maven-plugin</artifactId>
-        <configuration>
-          <instrumentation>
-            <!-- TODO: should this module have tests? -->
-            <excludes>
-              <exclude>**/**</exclude>
-            </excludes>
-          </instrumentation>
-        </configuration>
+        <executions>
+          <execution>
+            <goals>
+              <goal>clean</goal>
+            </goals>
+          </execution>
+        </executions>
       </plugin>
       <plugin>
         <groupId>org.codehaus.plexus</groupId>