You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ja...@apache.org on 2008/07/25 10:20:00 UTC

svn commit: r679698 - in /maven/sandbox/trunk/mercury/src: main/java/org/apache/maven/mercury/spi/http/client/ main/java/org/apache/maven/mercury/spi/http/client/deploy/ main/java/org/apache/maven/mercury/spi/http/client/retrieve/ main/java/org/apache/...

Author: janb
Date: Fri Jul 25 01:19:59 2008
New Revision: 679698

URL: http://svn.apache.org/viewvc?rev=679698&view=rev
Log:
Implemented StreamObservers and multiple checksum calcs for file downloads.

Added:
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/ChecksumCalculator.java
      - copied, changed from r679644, maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ChecksumCalculator.java
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1Verifier.java   (with props)
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1VerifierFactory.java   (with props)
Removed:
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ChecksumCalculator.java
Modified:
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/Binding.java
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/FileExchange.java
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ObservableInputStream.java
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ObservableOutputStream.java
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/deploy/FilePutExchange.java
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/DefaultRetriever.java
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/FileGetExchange.java
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/RetrievalTarget.java
    maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/api/Verifier.java
    maven/sandbox/trunk/mercury/src/test/java/org/apache/maven/mercury/spi/http/client/JettyDeployerTest.java
    maven/sandbox/trunk/mercury/src/test/java/org/apache/maven/mercury/spi/http/client/JettyRetrieverTest.java

Modified: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/Binding.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/Binding.java?rev=679698&r1=679697&r2=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/Binding.java (original)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/Binding.java Fri Jul 25 01:19:59 2008
@@ -32,7 +32,6 @@
 {
     protected String remoteUrl;
     protected File localFile;
-    protected boolean lenientChecksum;
        
     
     public Binding()
@@ -43,7 +42,6 @@
     {
         this.remoteUrl = remoteUrl;
         this.localFile = localFile;
-        this.lenientChecksum = lenientChecksum;
     }
 
     public String getRemoteUrl()
@@ -66,18 +64,10 @@
         this.localFile = localFile;
     }
 
-    public boolean isLenientChecksum()
-    {
-        return lenientChecksum;
-    }
-
-    public void setLenientChecksum( boolean leniantChecksum )
-    {
-        this.lenientChecksum = leniantChecksum;
-    }
+  
 
     public String toString()
     {
-        return "[" + remoteUrl + "," + localFile + "," + lenientChecksum + "]";
+        return "[" + remoteUrl + "," + localFile + "]";
     }
 }

Modified: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/FileExchange.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/FileExchange.java?rev=679698&r1=679697&r2=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/FileExchange.java (original)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/FileExchange.java Fri Jul 25 01:19:59 2008
@@ -36,10 +36,9 @@
     public static final String __BATCH_SUPPORTED_HEADER = "Jetty-Batch-Supported";
     public static final String __BATCH_COMMIT_HEADER = "Jetty-Batch-Commit";
     public static final String __BATCH_DISCARD_HEADER = "Jetty-Batch-Discard";
-    public static final String _digestAlgorithm = "SHA-1";
+
 
     protected HttpClient _httpClient;
-    protected boolean _digestRequired;
     protected int _status;
     protected String _url;
     protected File _localFile;
@@ -50,13 +49,12 @@
     public abstract void onFileError( String url, Exception e );
 
 
-    public FileExchange( Binding binding, File localFile, boolean digestRequired, HttpClient client )
+    public FileExchange( Binding binding, File localFile, HttpClient client )
     {
         _binding = binding;
         _url = binding.getRemoteUrl();
         _localFile = localFile;
         _httpClient = client;
-        _digestRequired = digestRequired;
         setURL( _url );
     }
 

Modified: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ObservableInputStream.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ObservableInputStream.java?rev=679698&r1=679697&r2=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ObservableInputStream.java (original)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ObservableInputStream.java Fri Jul 25 01:19:59 2008
@@ -26,6 +26,8 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import org.apache.maven.mercury.transport.api.StreamObserver;
+
 
 
 public class ObservableInputStream extends FilterInputStream

Modified: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ObservableOutputStream.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ObservableOutputStream.java?rev=679698&r1=679697&r2=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ObservableOutputStream.java (original)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ObservableOutputStream.java Fri Jul 25 01:19:59 2008
@@ -27,6 +27,8 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import org.apache.maven.mercury.transport.api.StreamObserver;
+
 
 
 public class ObservableOutputStream extends FilterOutputStream
@@ -42,13 +44,13 @@
     public void write(int b) throws IOException 
     {
         notifyListeners(b);
-        out.write(b);
+        this.out.write(b);
     }
 
     public void write(byte[] b, int off, int len) throws IOException 
     {  
         notifyListeners(b, off, len);
-        out.write(b, off, len);
+        this.out.write(b, off, len);
     }
     public void addObserver (StreamObserver o)
     {

Modified: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/deploy/FilePutExchange.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/deploy/FilePutExchange.java?rev=679698&r1=679697&r2=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/deploy/FilePutExchange.java (original)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/deploy/FilePutExchange.java Fri Jul 25 01:19:59 2008
@@ -20,9 +20,9 @@
 package org.apache.maven.mercury.spi.http.client.deploy;
 
 import org.apache.maven.mercury.spi.http.client.Binding;
-import org.apache.maven.mercury.spi.http.client.ChecksumCalculator;
 import org.apache.maven.mercury.spi.http.client.FileExchange;
 import org.apache.maven.mercury.spi.http.client.MercuryException;
+import org.apache.maven.mercury.transport.ChecksumCalculator;
 import org.mortbay.io.Buffer;
 import org.mortbay.jetty.HttpMethods;
 import org.mortbay.jetty.client.HttpClient;
@@ -45,7 +45,7 @@
  */
 public abstract class FilePutExchange extends FileExchange
 {
-
+    private boolean _digestRequired;
     private String _batchId;
     private InputStream _inputStream;
     private String _remoteRepoUrl;
@@ -56,9 +56,10 @@
     public abstract void onFileError( String url, Exception e );
 
 
-    public FilePutExchange( String batchId, Binding binding, File localFile, boolean digestRequired, HttpClient client )
+    public FilePutExchange( String batchId, Binding binding, File localFile, boolean isDigestRequired, HttpClient client )
     {
-        super( binding, localFile, digestRequired, client );
+        super( binding, localFile, client );
+        _digestRequired = isDigestRequired;
         _batchId = batchId;
     }
 
@@ -152,7 +153,7 @@
             }
             else
             {
-                MessageDigest digest = MessageDigest.getInstance( _digestAlgorithm );
+                MessageDigest digest = MessageDigest.getInstance( "SHA-1" );
                 _inputStream = new DigestInputStream( new FileInputStream( _localFile ), digest );
             }
         }

Modified: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/DefaultRetriever.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/DefaultRetriever.java?rev=679698&r1=679697&r2=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/DefaultRetriever.java (original)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/DefaultRetriever.java Fri Jul 25 01:19:59 2008
@@ -21,15 +21,25 @@
 
 import org.apache.maven.mercury.spi.http.client.Binding;
 import org.apache.maven.mercury.spi.http.client.MercuryException;
+import org.apache.maven.mercury.transport.api.Server;
+import org.apache.maven.mercury.transport.api.StreamObserver;
+import org.apache.maven.mercury.transport.api.StreamObserverFactory;
 import org.mortbay.jetty.client.HttpClient;
 
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
 public class DefaultRetriever implements Retriever
 {
     private HttpClient _httpClient;
+    private Set<Server> _servers = new HashSet<Server>();
+    
 
     public DefaultRetriever()
         throws MercuryException
@@ -66,7 +76,17 @@
             throw new MercuryException( null, "unable to start http client", e );
         }
     }
-
+                           
+    public void setServers (Set<Server>servers)
+    {
+        _servers.clear();
+        _servers.addAll(servers);
+    }
+    
+    public Set<Server> getServers()
+    {
+        return _servers;
+    }
 
     /**
      * Retrieve a set of artifacts and wait until all retrieved successfully
@@ -142,10 +162,14 @@
         for ( int i = 0; i < bindings.length && count.get() > 0; i++ )
         {
             final Binding binding = bindings[i];
+            
             RetrievalTarget target = null;
             try
             {
-                target = new RetrievalTarget( DefaultRetriever.this, binding, request.getValidators() )
+                Server server = resolveServer(binding);
+                Set<StreamObserver> observers = createStreamObservers(server);
+                
+                target = new RetrievalTarget( DefaultRetriever.this, binding, request.getValidators(), observers )
                 {
                     public void onComplete()
                     {
@@ -153,8 +177,7 @@
                         boolean checksumOK = verifyChecksum();
                         if ( !checksumOK )
                         {
-                            response.add( new MercuryException( binding,
-                                "Checksum failed: " + getRetrievedChecksum() + "!=" + getCalculatedChecksum() ) );
+                            response.add( new MercuryException( binding, "Checksum failed") );
                         }
 
                         //if the file checksum is ok, then apply the validators
@@ -210,6 +233,7 @@
                                 List<RetrievalTarget> targets )
     {
         boolean completor = count.decrementAndGet() == 0;
+        
         if ( !completor && request.isFailFast() && response.getExceptions().size() > 0 )
         {
             completor = count.getAndSet( 0 ) > 0;
@@ -248,5 +272,37 @@
     {
         return _httpClient;
     }
+    
+    private Server resolveServer (Binding binding)
+    throws MalformedURLException
+    {
+        if (binding.getRemoteUrl() == null)
+        return null;
+        
+        URL bindingURL = new URL(binding.getRemoteUrl());
+        Iterator<Server> itor = _servers.iterator();
+        Server server = null;
+        while(itor.hasNext() && server==null)
+        {
+            Server s = itor.next();
+            if (bindingURL.getProtocol().equalsIgnoreCase(s.getURL().getProtocol()) 
+                    && bindingURL.getHost().equalsIgnoreCase(s.getURL().getHost())
+                    && bindingURL.getPort() == s.getURL().getPort())
+                server = s;
+        }
+        return server;
+    }
+    
+    
+    private Set<StreamObserver> createStreamObservers (Server server)
+    {
+        HashSet<StreamObserver> observers = new HashSet<StreamObserver>();
+        Set<StreamObserverFactory> factories = server.getStreamObserverFactories();
+        for (StreamObserverFactory f:factories)
+        {
+            observers.add(f.newInstance());
+        }
+        return observers;
+    }
 
 }

Modified: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/FileGetExchange.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/FileGetExchange.java?rev=679698&r1=679697&r2=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/FileGetExchange.java (original)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/FileGetExchange.java Fri Jul 25 01:19:59 2008
@@ -19,23 +19,25 @@
 
 package org.apache.maven.mercury.spi.http.client.retrieve;
 
-import org.apache.maven.mercury.spi.http.client.Binding;
-import org.apache.maven.mercury.spi.http.client.ChecksumCalculator;
-import org.apache.maven.mercury.spi.http.client.FileExchange;
-import org.apache.maven.mercury.spi.http.client.MercuryException;
-import org.mortbay.io.Buffer;
-import org.mortbay.jetty.HttpMethods;
-import org.mortbay.jetty.client.HttpClient;
-
-import javax.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.security.DigestOutputStream;
-import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.maven.mercury.spi.http.client.Binding;
+import org.apache.maven.mercury.spi.http.client.FileExchange;
+import org.apache.maven.mercury.spi.http.client.MercuryException;
+import org.apache.maven.mercury.spi.http.client.ObservableOutputStream;
+import org.apache.maven.mercury.transport.api.StreamObserver;
+import org.mortbay.io.Buffer;
+import org.mortbay.jetty.HttpMethods;
+import org.mortbay.jetty.client.HttpClient;
 
 
 /**
@@ -50,18 +52,20 @@
 public abstract class FileGetExchange extends FileExchange
 {
     private OutputStream _outputStream;
+    private Set<StreamObserver> _observers = new HashSet<StreamObserver>();
 
     /**
      * Constructor.
      *
      * @param binding        the remote file to fetch
      * @param localFile      the local file location to store the remote file
-     * @param digestRequired if true, the file stream will be passed thru the digest calculator
+     * @param observers      observers of the io stream
      * @param client         async http client
      */
-    public FileGetExchange( Binding binding, File localFile, boolean digestRequired, HttpClient client )
+    public FileGetExchange( Binding binding, File localFile, Set<StreamObserver> observers, HttpClient client )
     {
-        super( binding, localFile, digestRequired, client );
+        super( binding, localFile, client );
+        _observers.addAll(observers);
     }
 
 
@@ -91,10 +95,12 @@
                 return;
             }
 
-            if ( _digestRequired && _outputStream != null )
+            if ( _outputStream != null )
             {
-                byte[] bytes = ( (DigestOutputStream) _outputStream ).getMessageDigest().digest();
-                digest = ChecksumCalculator.encodeToAsciiHex( bytes );
+                
+                /*
+             
+                */
             }
             onFileComplete( _url, _localFile, digest );
         }
@@ -138,16 +144,11 @@
     {
         if ( _outputStream == null )
         {
-            if ( !_digestRequired )
-            {
-                _outputStream = new FileOutputStream( _localFile );
-            }
-            else
-            {
-                MessageDigest digest = MessageDigest.getInstance( _digestAlgorithm );
-                _outputStream = new DigestOutputStream( new FileOutputStream( _localFile ), digest );
-            }
+            ObservableOutputStream oos = new ObservableOutputStream( new FileOutputStream( _localFile ));
+            oos.addObservers(_observers);
+            _outputStream = oos;
         }
+         
         return _outputStream;
     }
 }

Modified: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/RetrievalTarget.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/RetrievalTarget.java?rev=679698&r1=679697&r2=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/RetrievalTarget.java (original)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/RetrievalTarget.java Fri Jul 25 01:19:59 2008
@@ -23,12 +23,20 @@
 import org.apache.maven.mercury.spi.http.client.FileExchange;
 import org.apache.maven.mercury.spi.http.client.MercuryException;
 import org.apache.maven.mercury.spi.http.validate.Validator;
+import org.apache.maven.mercury.transport.api.StreamObserver;
+import org.apache.maven.mercury.transport.api.Verifier;
 import org.mortbay.jetty.client.HttpExchange;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
 import java.util.Set;
 
 
@@ -38,31 +46,31 @@
  * A RetrievalTarget is a remote file that must be downloaded locally, checksummed
  * and then atomically moved to its final location. The RetrievalTarget encapsulates
  * the temporary local file to which the remote file is downloaded, and also the
- * retrieval of the checksum file and the checksum calculation.
+ * retrieval of the checksum file(s) and the checksum calculation(s).
  */
 public abstract class RetrievalTarget
 {
     public static final String __PREFIX = "JTY_";
-    public static final String __DIGEST_SUFFIX = ".sha1";
     public static final String __TEMP_SUFFIX = ".tmp";
     public static final int __START_STATE = 1;
     public static final int __REQUESTED_STATE = 2;
     public static final int __READY_STATE = 3;
 
-    private int _checksumState;
-    private int _targetState;
+    protected int _checksumState;
+    protected int _targetState;
+    
+    protected MercuryException _exception;
+    protected Binding _binding;
+    protected File _tempFile;
+    protected DefaultRetriever _retriever;
+    protected boolean _complete;
+    protected HttpExchange _exchange;
+    protected Set<Validator> _validators;
+    protected Set<StreamObserver> _observers = new HashSet<StreamObserver>();
+    protected List<Verifier> _verifiers = new ArrayList<Verifier>();
+    protected Map<Verifier, String> _verifierMap = new HashMap<Verifier, String>();
+ 
     
-    private MercuryException _exception;
-    private Binding _binding;
-    private File _tempFile;
-    private String _checksumUrl;
-    private String _retrievedChecksum;
-    private String _calculatedChecksum;
-    private DefaultRetriever _retriever;
-    private boolean _complete;
-    private HttpExchange _exchange;
-    private Set<Validator> _validators;
-
     public abstract void onComplete();
 
     public abstract void onError( MercuryException exception );
@@ -73,7 +81,7 @@
      * @param binding
      * @param callback
      */
-    public RetrievalTarget( DefaultRetriever retriever, Binding binding, Set<Validator> validators )
+    public RetrievalTarget( DefaultRetriever retriever, Binding binding, Set<Validator> validators, Set<StreamObserver> observers )
     {
         if ( binding == null || binding.getRemoteUrl() == null || binding.getLocalFile() == null )
         {
@@ -82,9 +90,18 @@
         _retriever = retriever;
         _binding = binding;
         _validators = validators;
-        _checksumUrl = _binding.getRemoteUrl() + __DIGEST_SUFFIX;
+       
+        //sift out the potential checksum verifiers
+        for (StreamObserver o: observers)
+        {
+            if (Verifier.class.isAssignableFrom(o.getClass()))
+                _verifiers.add((Verifier)o);
+            else
+                _observers.add(o);
+        }
+        
         _tempFile = new File( _binding.getLocalFile().getParentFile(),
-            __PREFIX + _binding.getLocalFile().getName() + __TEMP_SUFFIX );        
+                              __PREFIX + _binding.getLocalFile().getName() + __TEMP_SUFFIX );        
         _tempFile.deleteOnExit();
         
         // Create the directory if it doesn't exist
@@ -104,30 +121,7 @@
         }
     }
 
-    public boolean isLenientChecksum()
-    {
-        return _binding.isLenientChecksum();
-    }
-
-    public void setRetrievedChecksum( String retrievedChecksum )
-    {
-        _retrievedChecksum = retrievedChecksum;
-    }
-
-    public String getExpectedChecksum()
-    {
-        return _retrievedChecksum;
-    }
-
-    public void setCalculatedChecksum( String calculatedChecksum )
-    {
-        _calculatedChecksum = calculatedChecksum;
-    }
-
-    public String getActualChecksum()
-    {
-        return _calculatedChecksum;
-    }
+   
 
     public File getTempFile()
     {
@@ -140,11 +134,20 @@
     }
 
 
-    /** Retrieve the remote file and its checksum file using jetty async httpclient. */
+    /** Start by getting the appropriate checksums */
     public void retrieve()
     {
-        updateChecksumState( __START_STATE, null );
-        updateTargetState( __START_STATE, null );
+        //if there are no checksum verifiers configured, proceed directly to get the file
+        if (_verifiers.size() == 0)
+        {
+            _checksumState = __READY_STATE;
+            updateTargetState(__START_STATE, null);
+        }
+        else
+        {
+            _checksumState = __START_STATE;
+            updateChecksumState(-1, null);
+        }
     }
 
 
@@ -164,6 +167,69 @@
         }
     }
 
+    public synchronized boolean isComplete()
+    {
+        return _complete;
+    }
+
+    public String toString()
+    {
+        return "T:" + _binding.getRemoteUrl() + ":" + _targetState + ":" + _checksumState + ":" + _complete;
+    }
+
+    private void updateChecksumState (int index, Throwable ex)
+    {
+        if ( _exception == null && ex != null )
+        {
+            if ( ex instanceof MercuryException )
+            {
+                _exception = (MercuryException) ex;
+            }
+            else
+            {
+                _exception = new MercuryException( _binding, ex );
+            }
+        }
+        
+        if (ex != null)
+        {
+            _checksumState = __READY_STATE;
+            onError(_exception);
+        }
+        else
+        {     
+            boolean proceedWithTargetFile = false;
+            if (index >= 0)
+            {
+                //check if the just-completed retrieval means that we can stop trying to download checksums 
+                Verifier v = _verifiers.get(index);
+                if (_verifierMap.containsKey(v) && v.isSufficient())
+                    proceedWithTargetFile = true;
+            }
+
+            index++;
+            
+            if ((index < _verifiers.size()) && !proceedWithTargetFile)
+            {
+                retrieveChecksum(index);
+            }
+            else
+            {
+                _checksumState = __READY_STATE;
+
+                //finished retrieving all possible checksums. Add all verifiers
+                //that had matching checksums into the observers list
+                _observers.addAll(_verifierMap.keySet());
+
+                //now get the file now we have the checksum sorted out
+                updateTargetState( __START_STATE, null );
+            }
+        }
+    }
+    
+    
+   
+   
 
     /**
      * Check the actual checksum against the expected checksum
@@ -172,18 +238,22 @@
      */
     public boolean verifyChecksum()
     {
-        if ( _retrievedChecksum != null && _calculatedChecksum != null && _calculatedChecksum.equals(
-            _retrievedChecksum ) )
-        {
-            return true;
-        }
-        else if ( _retrievedChecksum == null && _binding.isLenientChecksum() )
+        boolean ok = true;
+        
+        synchronized (_verifierMap)
         {
-            return true;
+            Iterator<Map.Entry<Verifier, String>> itor = _verifierMap.entrySet().iterator();
+            while (itor.hasNext() && ok)
+            {               
+                Map.Entry<Verifier, String> e = itor.next();
+                ok = e.getKey().verifySignature(e.getValue());
+            }
         }
-
-        return false;
+        
+        return ok;
     }
+        
+    
 
     public boolean validate( List<String> errors )
     {
@@ -218,40 +288,7 @@
         return true;
     }
 
-    protected synchronized void updateChecksumState( int state, Throwable ex )
-    {
-        _checksumState = state;
-        if ( _exception == null && ex != null )
-        {
-            if ( ex instanceof MercuryException )
-            {
-                _exception = (MercuryException) ex;
-            }
-            else
-            {
-                _exception = new MercuryException( _binding, ex );
-            }
-        }
-
-        if ( _checksumState == __START_STATE )
-        {
-            _exchange = retrieveChecksum();
-        }
-
-        //if both checksum and target file are ready, we're ready to return callback
-        if ( _checksumState == __READY_STATE && _targetState == __READY_STATE )
-        {
-            _complete = true;
-            if ( _exception == null )
-            {
-                onComplete();
-            }
-            else
-            {
-                onError( _exception );
-            }
-        }
-    }
+  
 
     protected synchronized void updateTargetState( int state, Throwable ex )
     {
@@ -274,7 +311,7 @@
         }
 
         //if both checksum and target file are ready, we're ready to return callback
-        if ( _checksumState == __READY_STATE && _targetState == __READY_STATE )
+        if (_targetState == __READY_STATE )
         {
             _complete = true;
             if ( _exception == null )
@@ -289,28 +326,53 @@
     }
 
     /** Asynchronously fetch the checksum for the target file. */
-    private HttpExchange retrieveChecksum()
+    private HttpExchange retrieveChecksum(final int index)
     {
-        updateChecksumState( __REQUESTED_STATE, null );
         HttpExchange exchange = new HttpExchange.ContentExchange()
         {
             protected void onException( Throwable ex )
             {
-                updateChecksumState( __READY_STATE, ex );
+                //if the checksum is mandatory, then propagate the exception and stop processing
+                if (!_verifiers.get(index).isLenient())
+                {
+                    updateChecksumState(index, ex);
+                }
+                else
+                    updateChecksumState(index, null);
+                
             }
 
             protected void onResponseComplete() throws IOException
             {
                 super.onResponseComplete();
+                Verifier v = _verifiers.get(index);
+                
                 if ( getResponseStatus() == HttpServletResponse.SC_OK )
                 {
-                    setRetrievedChecksum( getResponseContent().trim() );
+                    //We got a checksum so match it up with the verifier it is for
+                    synchronized (_verifierMap)
+                    {
+                        if (v.isSufficient())
+                            _verifierMap.clear(); //remove all other entries, we only need one checksum
+                        
+                        _verifierMap.put(v, getResponseContent());
+                    }
+                    updateChecksumState(index, null);
+                }
+                else 
+                {
+                    if (!v.isLenient()) 
+                    {
+                        //checksum file MUST be present, fail
+                        updateChecksumState(index, new Exception ("Mandatory checksum file not found "+this.getURI()));
+                    }
+                    else
+                        updateChecksumState(index, null);
                 }
-
-                updateChecksumState( __READY_STATE, null );
             }
         };
-        exchange.setURL( _checksumUrl );
+        
+        exchange.setURL( getChecksumFileURLAsString( _verifiers.get(index)) );
 
         try
         {
@@ -318,7 +380,7 @@
         }
         catch ( IOException ex )
         {
-            updateChecksumState( __READY_STATE, ex );
+            updateChecksumState(index, ex);
         }
         return exchange;
     }
@@ -330,13 +392,12 @@
         updateTargetState( __REQUESTED_STATE, null );
 
         //get the file, calculating the digest for it on the fly
-        FileExchange exchange = new FileGetExchange( _binding, getTempFile(), true, _retriever.getHttpClient() )
+        FileExchange exchange = new FileGetExchange( _binding, getTempFile(), _observers, _retriever.getHttpClient() )
         {
             public void onFileComplete( String url, File localFile, String digest )
             {
                 //we got the target file ok, so tell our main callback
                 _targetState = __READY_STATE;
-                setCalculatedChecksum( digest );
                 updateTargetState( __READY_STATE, null );
             }
 
@@ -351,6 +412,13 @@
         return exchange;
     }
 
+    private String getChecksumFileURLAsString (Verifier verifier)
+    {
+        String extension = verifier.getExtension();
+        if (extension.charAt(0) != '.')
+            extension = "."+extension;
+        return _binding.getRemoteUrl() + extension;
+    }
 
     private boolean deleteTempFile()
     {
@@ -360,24 +428,5 @@
         }
         return false;
     }
-
-    public synchronized boolean isComplete()
-    {
-        return _complete;
-    }
-
-    public String toString()
-    {
-        return "T:" + _binding.getRemoteUrl() + ":" + _targetState + ":" + _checksumState + ":" + _complete;
-    }
-
-    public String getRetrievedChecksum()
-    {
-        return _retrievedChecksum;
-    }
-
-    public String getCalculatedChecksum()
-    {
-        return _calculatedChecksum;
-    }
+    
 }

Copied: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/ChecksumCalculator.java (from r679644, maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ChecksumCalculator.java)
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/ChecksumCalculator.java?p2=maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/ChecksumCalculator.java&p1=maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ChecksumCalculator.java&r1=679644&r2=679698&rev=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/spi/http/client/ChecksumCalculator.java (original)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/ChecksumCalculator.java Fri Jul 25 01:19:59 2008
@@ -17,15 +17,9 @@
  * under the License.
  */
 
-package org.apache.maven.mercury.spi.http.client;
+package org.apache.maven.mercury.transport;
 
-import org.mortbay.util.IO;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
 
 public class ChecksumCalculator
 {
@@ -46,38 +40,4 @@
 
         return new String( raw );
     }
-
-    public static String readChecksumFromFile( File f ) throws FileNotFoundException, IOException
-    {
-        if ( f == null )
-        {
-            return null;
-        }
-        if ( !isChecksumFile( f ) )
-        {
-            throw new IOException( "Not a checksum file" );
-        }
-
-        FileInputStream fis = new FileInputStream( f );
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        IO.copy( fis, baos );
-        return baos.toString( "UTF-8" );
-    }
-
-    public static boolean isChecksumFile( File f )
-    {
-        if ( f == null )
-        {
-            return false;
-        }
-
-        String fileName = f.getName().toLowerCase();
-        if ( fileName.endsWith( ".sha" ) || fileName.endsWith( ".sha1" ) )
-        {
-            return true;
-        }
-
-        return false;
-    }
-
 }

Added: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1Verifier.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1Verifier.java?rev=679698&view=auto
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1Verifier.java (added)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1Verifier.java Fri Jul 25 01:19:59 2008
@@ -0,0 +1,114 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file                                                                                            
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.maven.mercury.transport;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import org.apache.maven.mercury.transport.api.Verifier;
+
+/**
+ * SHA1Verifier
+ *
+ *
+ */
+public class SHA1Verifier implements Verifier
+{
+    public static final String digestAlgorithm = "SHA-1";
+    private MessageDigest digest;
+    private byte[] digestBytes;
+    private boolean isLenient;
+    private boolean isSufficient;
+    
+    
+    public SHA1Verifier (boolean isLenient, boolean isSufficient)
+    {
+        this.isLenient = isLenient;
+        this.isSufficient = isSufficient;
+        try
+        {
+            digest = MessageDigest.getInstance( digestAlgorithm );
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            //TODO
+        }
+    }
+
+    public String getExtension()
+    {
+        return ".sha1";
+    }
+
+    public byte[] getSignatureBytes ()
+    {
+        if (digestBytes == null)
+            digestBytes = digest.digest();
+        return digestBytes;
+    }
+    
+    public String getSignature()
+    {
+        return ChecksumCalculator.encodeToAsciiHex( getSignatureBytes() );
+    }
+    
+    public void setLenient (boolean lenient)
+    {
+        isLenient = lenient;
+    }
+
+    public boolean isLenient()
+    {
+        return isLenient;
+    }
+
+    public void setSufficient (boolean sufficient)
+    {
+        isSufficient = sufficient;
+    }
+    public boolean isSufficient()
+    {
+        return isSufficient;
+    }
+
+    public boolean verifySignature(String sig)
+    {
+        String calculatedSignature = getSignature();
+        if (calculatedSignature == null && sig == null)
+            return true;
+        if ((calculatedSignature != null) && calculatedSignature.equals(sig))
+            return true;
+        return false;
+    }
+
+    public void byteReady(int b)
+    {
+        if (digest != null)
+            digest.update((byte)b);
+    }
+
+    public void bytesReady(byte[] b, int off, int len)
+    {
+        if (digest != null)
+            digest.update(b, off, len);
+    }
+
+}

Propchange: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1Verifier.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1Verifier.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1Verifier.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1VerifierFactory.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1VerifierFactory.java?rev=679698&view=auto
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1VerifierFactory.java (added)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1VerifierFactory.java Fri Jul 25 01:19:59 2008
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file                                                                                            
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.maven.mercury.transport;
+
+import org.apache.maven.mercury.transport.api.StreamObserver;
+import org.apache.maven.mercury.transport.api.StreamObserverFactory;
+
+public class SHA1VerifierFactory implements StreamObserverFactory
+{
+    private boolean isLenient;
+    private boolean isSufficient;
+
+    public SHA1VerifierFactory (boolean isLenient, boolean isSufficient)
+    {
+        this.isLenient = isLenient;
+        this.isSufficient = isSufficient;
+    }
+    public StreamObserver newInstance()
+    {
+       return new SHA1Verifier(this.isLenient, this.isSufficient);
+    }
+
+}

Propchange: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1VerifierFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1VerifierFactory.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/SHA1VerifierFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/api/Verifier.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/api/Verifier.java?rev=679698&r1=679697&r2=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/api/Verifier.java (original)
+++ maven/sandbox/trunk/mercury/src/main/java/org/apache/maven/mercury/transport/api/Verifier.java Fri Jul 25 01:19:59 2008
@@ -21,7 +21,7 @@
 public interface Verifier extends StreamObserver
 {
     public String getSignature();
-    public void verifySignature (String signature);
+    public boolean verifySignature (String signature);
     public boolean isLenient();
     public boolean isSufficient();
     public String getExtension();

Modified: maven/sandbox/trunk/mercury/src/test/java/org/apache/maven/mercury/spi/http/client/JettyDeployerTest.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/test/java/org/apache/maven/mercury/spi/http/client/JettyDeployerTest.java?rev=679698&r1=679697&r2=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/test/java/org/apache/maven/mercury/spi/http/client/JettyDeployerTest.java (original)
+++ maven/sandbox/trunk/mercury/src/test/java/org/apache/maven/mercury/spi/http/client/JettyDeployerTest.java Fri Jul 25 01:19:59 2008
@@ -200,9 +200,10 @@
         _binding0.setLocalFile(_file0);
         bindings.add(_binding0);
         
+        //TODO Test Lenient
         _binding1.setRemoteUrl(_HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file1.txt"); //has no sha file
         _binding1.setLocalFile(_file1);
-        _binding1.setLenientChecksum(true);
+        //_binding1.setLenientChecksum(true);
         bindings.add(_binding1);
       
         _binding3.setRemoteUrl(_HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file3.jar");
@@ -221,7 +222,7 @@
         
         DeployResponse response = _deployer.deploy(request);
 
-        //for (BatchException t:response.getExceptions())
+        //for (MercuryException t:response.getExceptions())
         //    t.printStackTrace();
         
         assertEquals(10, _putServer.getPutDir().list().length);
@@ -376,7 +377,7 @@
         request.setFailFast(true);
         DeployResponse response = _deployer.deploy(request);
 
-        //for (BatchException t:response.getExceptions())
+        //for (MercuryException t:response.getExceptions())
         //    t.printStackTrace();
         
         //with failfast==true and the server side not running the mercury enhancements, we have no way to know

Modified: maven/sandbox/trunk/mercury/src/test/java/org/apache/maven/mercury/spi/http/client/JettyRetrieverTest.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/mercury/src/test/java/org/apache/maven/mercury/spi/http/client/JettyRetrieverTest.java?rev=679698&r1=679697&r2=679698&view=diff
==============================================================================
--- maven/sandbox/trunk/mercury/src/test/java/org/apache/maven/mercury/spi/http/client/JettyRetrieverTest.java (original)
+++ maven/sandbox/trunk/mercury/src/test/java/org/apache/maven/mercury/spi/http/client/JettyRetrieverTest.java Fri Jul 25 01:19:59 2008
@@ -28,8 +28,15 @@
 import org.apache.maven.mercury.spi.http.client.retrieve.RetrievalResponse;
 import org.apache.maven.mercury.spi.http.server.SimpleTestServer;
 import org.apache.maven.mercury.spi.http.validate.Validator;
+import org.apache.maven.mercury.transport.SHA1Verifier;
+import org.apache.maven.mercury.transport.SHA1VerifierFactory;
+import org.apache.maven.mercury.transport.api.Server;
+import org.apache.maven.mercury.transport.api.StreamObserver;
+import org.apache.maven.mercury.transport.api.StreamObserverFactory;
+import org.apache.maven.mercury.transport.api.Verifier;
 
 import java.io.File;
+import java.net.URL;
 import java.util.HashSet;
 import java.util.List;
 
@@ -52,8 +59,10 @@
     Binding binding5 = new Binding();
     DefaultRetriever retriever;
     SimpleTestServer server;
+    Server remoteServerType;
+    HashSet<StreamObserverFactory> factories;
     
-    
+
     public class TxtValidator implements Validator 
     {
 
@@ -84,13 +93,11 @@
     {
         public String getFileExtension()
         {
-            System.err.println("Returning extension for AlwaysFalseTxtValidator");
             return "txt";
         }
 
         public boolean validate(String stagedFile, List<String> errors)
         {
-            System.err.println("Evaluating "+stagedFile);
             errors.add("Always false");
             return false;
         }
@@ -99,11 +106,18 @@
     public void setUp ()
     throws Exception
     {
-        retriever = new DefaultRetriever();
-        
         server = new SimpleTestServer();
         server.start();
         _port=String.valueOf(server.getPort()); 
+        
+        HashSet<Server> remoteServerTypes = new HashSet<Server>();
+        remoteServerType = new Server(new URL(__HOST_FRAGMENT+_port));
+        factories = new HashSet<StreamObserverFactory>();
+            
+        remoteServerTypes.add(remoteServerType);
+        
+        retriever = new DefaultRetriever();
+        retriever.setServers(remoteServerTypes);
     }
     
     
@@ -132,6 +146,9 @@
     public void testSyncRetrievalAllGood()
     throws Exception
     {
+        factories.add(new SHA1VerifierFactory(false, true)); //!lenient, sufficient
+        remoteServerType.setStreamObserverFactories(factories);
+        
         //make local dir to put stuff in
         final File dir = mkTempDir();
         DefaultRetrievalRequest request = new DefaultRetrievalRequest();
@@ -171,8 +188,8 @@
         
         RetrievalResponse response = retriever.retrieve(request);
         
-//        for (BatchException t:response.getExceptions())
-//            t.printStackTrace();
+        //for (MercuryException t:response.getExceptions())
+        //    t.printStackTrace();
         
         assertEquals(2,response.getExceptions().size());
         assertTrue(!file0.exists());
@@ -188,6 +205,9 @@
     public void testSyncRetrievalFailFast()
         throws Exception
     {
+        factories.add(new SHA1VerifierFactory(false, true)); //!lenient, sufficient
+        remoteServerType.setStreamObserverFactories(factories);
+        
         //make local dir to put stuff in
         final File dir = mkTempDir();
         DefaultRetrievalRequest request = new DefaultRetrievalRequest();
@@ -205,12 +225,10 @@
 
         binding1.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file1.txt"); //has no sha file
         binding1.setLocalFile(file1);
-        binding1.setLenientChecksum(false);
         bindings.add(binding1);
 
         binding2.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file2.txt"); //has wrong sha file
         binding2.setLocalFile(file2);
-        binding2.setLenientChecksum(true);
         bindings.add(binding2);
 
         binding3.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file3.jar");
@@ -234,7 +252,7 @@
         
         RetrievalResponse response = retriever.retrieve(request);
 
-        //for (BatchException t:response.getExceptions())
+        //for (MercuryException t:response.getExceptions())
         //   t.printStackTrace();
 
         assertTrue(!file0.exists());
@@ -250,6 +268,9 @@
     public void testSyncRetrievalLenient0()
         throws Exception
     {
+        factories.add(new SHA1VerifierFactory(true, true)); //lenient, sufficient
+        remoteServerType.setStreamObserverFactories(factories);
+        
         //make local dir to put stuff in
         final File dir = mkTempDir();
         DefaultRetrievalRequest request = new DefaultRetrievalRequest();
@@ -267,12 +288,10 @@
 
         binding1.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file1.txt"); //has no sha file
         binding1.setLocalFile(file1);
-        binding1.setLenientChecksum(true);
         bindings.add(binding1);
 
         binding2.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file2.txt"); //has wrong sha file
         binding2.setLocalFile(file2);
-        binding2.setLenientChecksum(true);
         bindings.add(binding2);
 
         binding3.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file3.jar");
@@ -304,6 +323,8 @@
     public void testSyncRetrievalLenient1()
     throws Exception
     {
+        factories.add(new SHA1VerifierFactory(true, true)); //lenient, sufficient
+        remoteServerType.setStreamObserverFactories(factories);
         //make local dir to put stuff in
         final File dir = mkTempDir();
         DefaultRetrievalRequest request = new DefaultRetrievalRequest();
@@ -321,7 +342,6 @@
 
         binding1.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file1.txt"); //has no sha file
         binding1.setLocalFile(file1);
-        binding1.setLenientChecksum(true);
         bindings.add(binding1);
 
         binding3.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file3.jar");
@@ -340,8 +360,8 @@
         request.setFailFast(false);
         RetrievalResponse response = retriever.retrieve(request);
 
-        for (MercuryException t:response.getExceptions())
-            t.printStackTrace();
+        //for (MercuryException t:response.getExceptions())
+        //    t.printStackTrace();
 
         assertEquals(0,response.getExceptions().size());
         assertTrue(file0.exists());
@@ -355,60 +375,65 @@
     
     public void testValidatorSuccess() throws Exception
     {
-            //make local dir to put stuff in
-            final File dir = mkTempDir();
-            DefaultRetrievalRequest request = new DefaultRetrievalRequest();
-            HashSet<Binding> bindings = new HashSet<Binding>();
-            HashSet<Validator> validators = new HashSet<Validator>();
-            validators.add(new TxtValidator());
-            request.setValidators(validators);
-
-            file0 = new File(dir, "file0.txt");
-            file1 = new File(dir, "file1.txt");
-            file2 = new File(dir, "file2.txt");
-            file3 = new File(dir, "file3.jar");
-            file4 = new File(dir, "file4.so");
-            file5 = new File(dir, "file5.jpg");
-            binding0.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file0.txt");
-            binding0.setLocalFile(file0);
-            bindings.add(binding0);
-
-            binding1.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file1.txt"); //has no sha file
-            binding1.setLocalFile(file1);
-            binding1.setLenientChecksum(true);
-            bindings.add(binding1);
-
-            binding3.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file3.jar");
-            binding3.setLocalFile(file3);
-            bindings.add(binding3);
-
-            binding4.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file4.so");
-            binding4.setLocalFile(file4);
-            bindings.add(binding4);
-
-            binding5.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file5.jpg");
-            binding5.setLocalFile(file5);
-            bindings.add(binding5);
-
-            request.setFailFast(false);
-
-            request.setBindings(bindings);
-            RetrievalResponse response = retriever.retrieve(request);
-
-            //for (BatchException t:response.getExceptions())
-            //    t.printStackTrace();
-
-            assertEquals(0,response.getExceptions().size());
-            assertTrue(file0.exists());
-            assertTrue(file1.exists());
-            assertTrue(!file2.exists());
-            assertTrue(file3.exists());
-            assertTrue(file4.exists());
-            assertTrue(file5.exists());
+        factories.add(new SHA1VerifierFactory(true, true)); //lenient, sufficient
+        remoteServerType.setStreamObserverFactories(factories);
+
+        //make local dir to put stuff in
+        final File dir = mkTempDir();
+        DefaultRetrievalRequest request = new DefaultRetrievalRequest();
+        HashSet<Binding> bindings = new HashSet<Binding>();
+        HashSet<Validator> validators = new HashSet<Validator>();
+        validators.add(new TxtValidator());
+        request.setValidators(validators);
+
+        file0 = new File(dir, "file0.txt");
+        file1 = new File(dir, "file1.txt");
+        file2 = new File(dir, "file2.txt");
+        file3 = new File(dir, "file3.jar");
+        file4 = new File(dir, "file4.so");
+        file5 = new File(dir, "file5.jpg");
+        binding0.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file0.txt");
+        binding0.setLocalFile(file0);
+        bindings.add(binding0);
+
+        binding1.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file1.txt"); //has no sha file
+        binding1.setLocalFile(file1);
+        bindings.add(binding1);
+
+        binding3.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file3.jar");
+        binding3.setLocalFile(file3);
+        bindings.add(binding3);
+
+        binding4.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file4.so");
+        binding4.setLocalFile(file4);
+        bindings.add(binding4);
+
+        binding5.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file5.jpg");
+        binding5.setLocalFile(file5);
+        bindings.add(binding5);
+
+        request.setFailFast(false);
+
+        request.setBindings(bindings);
+        RetrievalResponse response = retriever.retrieve(request);
+
+        //for (MercuryException t:response.getExceptions())
+        //    t.printStackTrace();
+
+        assertEquals(0,response.getExceptions().size());
+        assertTrue(file0.exists());
+        assertTrue(file1.exists());
+        assertTrue(!file2.exists());
+        assertTrue(file3.exists());
+        assertTrue(file4.exists());
+        assertTrue(file5.exists());
     }
     
     public void testValidatorFailure () throws Exception
     {
+        factories.add(new SHA1VerifierFactory(true, true)); //lenient, sufficient
+        remoteServerType.setStreamObserverFactories(factories);
+        
         //make local dir to put stuff in
         final File dir = mkTempDir();
         DefaultRetrievalRequest request = new DefaultRetrievalRequest();
@@ -429,7 +454,6 @@
 
         binding1.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file1.txt"); //has no sha file
         binding1.setLocalFile(file1);
-        binding1.setLenientChecksum(true);
         bindings.add(binding1);
 
         binding3.setRemoteUrl(__HOST_FRAGMENT+_port+__PATH_FRAGMENT+"file3.jar");
@@ -449,7 +473,7 @@
         request.setBindings(bindings);
         RetrievalResponse response = retriever.retrieve(request);
 
-        //for (BatchException t:response.getExceptions())
+        //for (MercuryException t:response.getExceptions())
         //    t.printStackTrace();
 
         assertEquals(2,response.getExceptions().size());