You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by jd...@apache.org on 2008/02/25 21:12:06 UTC

svn commit: r630977 - in /maven/artifact/trunk: ./ src/main/java/org/apache/maven/artifact/manager/ src/main/java/org/apache/maven/artifact/repository/metadata/ src/main/java/org/apache/maven/artifact/resolver/ src/test/java/org/apache/maven/artifact/m...

Author: jdcasey
Date: Mon Feb 25 12:12:03 2008
New Revision: 630977

URL: http://svn.apache.org/viewvc?rev=630977&view=rev
Log:
Improve updateInterval calculations for both artifacts and metadata, consolidated in one place...also, try to improve forced and interval triggered update behaviors.

Patch submitted by: Igor Fedorenko

Added:
    maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManager.java   (with props)
    maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/UpdateCheckManager.java   (with props)
    maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManagerTest.java   (with props)
    maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.java   (with props)
    maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestFileWagon.java   (with props)
    maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestTransferListener.java   (with props)
    maven/artifact/trunk/src/test/resources/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.xml   (with props)
Removed:
    maven/artifact/trunk/src/main/java/org/apache/maven/artifact/repository/metadata/MetadataTouchfile.java
    maven/artifact/trunk/src/test/java/org/apache/maven/artifact/repository/metadata/MetadataTouchfileTest.java
Modified:
    maven/artifact/trunk/pom.xml
    maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java
    maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/WagonManager.java
    maven/artifact/trunk/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java
    maven/artifact/trunk/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java
    maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/WagonNoOp.java
    maven/artifact/trunk/src/test/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManagerTest.java

Modified: maven/artifact/trunk/pom.xml
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/pom.xml?rev=630977&r1=630976&r2=630977&view=diff
==============================================================================
--- maven/artifact/trunk/pom.xml (original)
+++ maven/artifact/trunk/pom.xml Mon Feb 25 12:12:03 2008
@@ -43,7 +43,7 @@
     <dependency>
       <groupId>org.codehaus.plexus</groupId>
       <artifactId>plexus-container-default</artifactId>
-      <version>1.0-alpha-43</version>
+      <version>1.0-alpha-44</version>
     </dependency>
     <dependency>
       <groupId>org.apache.maven.wagon</groupId>

Added: maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManager.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManager.java?rev=630977&view=auto
==============================================================================
--- maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManager.java (added)
+++ maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManager.java Mon Feb 25 12:12:03 2008
@@ -0,0 +1,300 @@
+package org.apache.maven.artifact.manager;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.util.Date;
+import java.util.Properties;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.logging.Logger;
+import org.codehaus.plexus.util.IOUtil;
+
+/** @plexus.component */
+public class DefaultUpdateCheckManager
+    extends AbstractLogEnabled
+    implements UpdateCheckManager
+{
+
+    public DefaultUpdateCheckManager()
+    {
+
+    }
+
+    public DefaultUpdateCheckManager( Logger logger )
+    {
+        enableLogging( logger );
+    }
+
+    public static final String LAST_UPDATE_TAG = ".lastUpdated";
+
+    public static final String TOUCHFILE_NAME = "resolver-status.properties";
+
+    public boolean isUpdateRequired( Artifact artifact, ArtifactRepository repository )
+    {
+        ArtifactRepositoryPolicy policy = artifact.isSnapshot() ? repository.getSnapshots() : repository.getReleases();
+
+        File file = artifact.getFile();
+
+        if ( !policy.isEnabled() )
+        {
+            return false;
+        }
+
+        if ( file == null )
+        {
+            // TODO throw something instead?
+            return true;
+        }
+
+        Date lastCheckDate;
+        
+        if ( file.exists() )
+        {
+            lastCheckDate = new Date ( file.lastModified() );
+        }
+        else
+        {
+            lastCheckDate = getLastModifiedFromTouchfile( file );
+        }
+
+        return lastCheckDate == null || policy.checkOutOfDate( lastCheckDate );
+    }
+
+    public boolean isUpdateRequired( RepositoryMetadata metadata, ArtifactRepository repository, File file )
+    {
+        ArtifactRepositoryPolicy policy = metadata.isSnapshot() ? repository.getSnapshots() : repository.getReleases();
+
+        if ( !policy.isEnabled() )
+        {
+            return false;
+        }
+
+        if ( file == null )
+        {
+            // TODO throw something instead?
+            return true;
+        }
+
+        Date lastCheckDate = getLastModifiedFromTouchfile( file );
+
+        return lastCheckDate == null || policy.checkOutOfDate( lastCheckDate );
+    }
+
+    public void touch( Artifact artifact, ArtifactRepository repository )
+    {
+        File file = artifact.getFile();
+
+        touch( file, false );
+    }
+
+    public void touch( RepositoryMetadata metadata, ArtifactRepository repository, File file )
+    {
+        touch( file, true );
+    }
+
+    private void touch( File file, boolean forceTouchFile )
+    {
+        String name = file.getName();
+
+        File touchfile = getTouchfile( file );
+
+        synchronized ( touchfile.getAbsolutePath().intern() )
+        {
+            if ( !touchfile.getParentFile().exists() && !touchfile.getParentFile().mkdirs() )
+            {
+                getLogger().debug(
+                                   "Failed to create directory: " + touchfile.getParent() +
+                                       " for tracking artifact metadata resolution." );
+                return;
+            }
+
+            FileChannel channel = null;
+            FileLock lock = null;
+            try
+            {
+                Properties props = new Properties();
+
+                channel = new RandomAccessFile( touchfile, "rw" ).getChannel();
+                lock = channel.lock( 0, channel.size(), false );
+
+                if ( touchfile.canRead() )
+                {
+                    getLogger().debug( "Reading resolution-state from: " + touchfile );
+                    ByteBuffer buffer = ByteBuffer.allocate( (int) channel.size() );
+
+                    channel.read( buffer );
+                    buffer.flip();
+
+                    ByteArrayInputStream stream = new ByteArrayInputStream( buffer.array() );
+                    props.load( stream );
+                }
+
+                String key = getKey( name );
+
+                boolean modified = false;
+
+                if ( !forceTouchFile && file.exists() )
+                {
+                    modified = props.remove( key ) != null;
+                }
+                else
+                {
+                    props.setProperty( key, Long.toString( System.currentTimeMillis() ) );
+
+                    modified = true;
+                }
+
+                if ( modified )
+                {
+                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
+
+                    getLogger().debug( "Writing resolution-state to: " + touchfile );
+                    props.store( stream, "Last modified on: " + new Date() );
+
+                    byte[] data = stream.toByteArray();
+                    ByteBuffer buffer = ByteBuffer.allocate( data.length );
+                    buffer.put( data );
+                    buffer.flip();
+
+                    channel.position( 0 );
+                    channel.write( buffer );
+                }
+            }
+            catch ( IOException e )
+            {
+                getLogger().debug(
+                                   "Failed to record lastUpdated information for metadata resolution.\nMetadata type: " +
+                                       name, e );
+            }
+            finally
+            {
+                if ( lock != null )
+                {
+                    try
+                    {
+                        lock.release();
+                    }
+                    catch ( IOException e )
+                    {
+                        getLogger().debug(
+                                           "Error releasing exclusive lock for metadata resolution tracking file: " +
+                                               touchfile, e );
+                    }
+                }
+
+                if ( channel != null )
+                {
+                    try
+                    {
+                        channel.close();
+                    }
+                    catch ( IOException e )
+                    {
+                        getLogger().debug(
+                                           "Error closing FileChannel for metadata resolution tracking file: " +
+                                               touchfile, e );
+                    }
+                }
+            }
+        }
+    }
+
+    private String getKey( String name )
+    {
+        String key = name + LAST_UPDATE_TAG;
+        return key;
+    }
+
+    public Date getLastModifiedFromTouchfile( File file )
+    {
+        File touchfile = getTouchfile( file );
+
+        if ( !touchfile.canRead() )
+        {
+            return null;
+        }
+
+        String name = file.getName();
+
+        synchronized ( touchfile.getAbsolutePath().intern() )
+        {
+            String key = getKey( name );
+
+            getLogger().debug( "Searching for: " + key + " in touchfile." );
+
+            Date result = null;
+            FileInputStream stream = null;
+            FileLock lock = null;
+            try
+            {
+                Properties props = new Properties();
+
+                if ( touchfile.exists() )
+                {
+                    stream = new FileInputStream( touchfile );
+                    FileChannel channel = stream.getChannel();
+                    lock = channel.lock( 0, channel.size(), true );
+
+                    getLogger().debug( "Reading resolution-state from: " + touchfile );
+                    props.load( stream );
+
+                    String rawVal = props.getProperty( key );
+                    if ( rawVal != null )
+                    {
+                        try
+                        {
+                            result = new Date( Long.parseLong( rawVal ) );
+                        }
+                        catch ( NumberFormatException e )
+                        {
+                            getLogger().debug( "Cannot parse lastUpdated date: \'" + rawVal + "\'. Ignoring.", e );
+                            result = null;
+                        }
+                    }
+                }
+            }
+            catch ( IOException e )
+            {
+                getLogger().debug(
+                                   "Failed to read lastUpdated information for metadata resolution.\nMetadata type: " +
+                                       name, e );
+            }
+            finally
+            {
+                if ( lock != null )
+                {
+                    try
+                    {
+                        lock.release();
+                    }
+                    catch ( IOException e )
+                    {
+                        getLogger().debug(
+                                           "Error releasing shared lock for metadata resolution tracking file: " +
+                                               touchfile, e );
+                    }
+                }
+
+                IOUtil.close( stream );
+            }
+
+            return result;
+        }
+    }
+
+    private File getTouchfile( File file )
+    {
+        return new File( file.getParent(), TOUCHFILE_NAME );
+    }
+}

Propchange: maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManager.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Modified: maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java?rev=630977&r1=630976&r2=630977&view=diff
==============================================================================
--- maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java (original)
+++ maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java Mon Feb 25 12:12:03 2008
@@ -19,6 +19,15 @@
  * under the License.
  */
 
+import java.io.File;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
 import org.apache.maven.artifact.repository.ArtifactRepository;
@@ -112,6 +121,9 @@
     /** encapsulates access to Server credentials */
     private CredentialsDataSource credentialsDataSource;
 
+    /** @plexus.requirement */
+    private UpdateCheckManager updateCheckManager;
+
     // TODO: this leaks the component in the public api - it is never released back to the container
     public Wagon getWagon( Repository repository )
         throws UnsupportedProtocolException, WagonConfigurationException
@@ -318,7 +330,15 @@
     // NOTE: It is not possible that this method throws TransferFailedException under current conditions.
     // FIXME: Change the throws clause to reflect the fact that we're never throwing TransferFailedException
     public void getArtifact( Artifact artifact,
-                             List remoteRepositories )
+                             List remoteRepositories  )
+        throws TransferFailedException, ResourceDoesNotExistException
+	{
+    	getArtifact( artifact, remoteRepositories, true );
+	}
+
+    public void getArtifact( Artifact artifact,
+                             List remoteRepositories,
+                             boolean force )
         throws TransferFailedException, ResourceDoesNotExistException
     {
         boolean successful = false;
@@ -329,7 +349,7 @@
 
             try
             {
-                getArtifact( artifact, repository );
+                getArtifact( artifact, repository, force );
 
                 successful = artifact.isResolved();
             }
@@ -355,8 +375,17 @@
         }
     }
 
-    public void getArtifact( Artifact artifact,
+    public void getArtifact( Artifact artifact, 
                              ArtifactRepository repository )
+        throws TransferFailedException, 
+               ResourceDoesNotExistException
+    {
+        getArtifact( artifact, repository, true );
+    }
+
+    public void getArtifact( Artifact artifact,
+                             ArtifactRepository repository,
+                             boolean force )
         throws TransferFailedException, ResourceDoesNotExistException
     {
         String remotePath = repository.pathOf( artifact );
@@ -371,11 +400,18 @@
         {
             getLogger().debug( "Skipping blacklisted repository " + repository.getId() );
         }
-        else
+        else if ( force || updateCheckManager.isUpdateRequired( artifact, repository ) )
         {
             getLogger().debug( "Trying repository " + repository.getId() );
 
-            getRemoteFile( repository, artifact.getFile(), remotePath, downloadMonitor, policy.getChecksumPolicy(), false );
+            try
+            {
+            	getRemoteFile( repository, artifact.getFile(), remotePath, downloadMonitor, policy.getChecksumPolicy(), false );
+            }
+            finally
+            {
+            	updateCheckManager.touch( artifact, repository );
+            }
 
             getLogger().debug( "  Artifact resolved" );
 

Added: maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/UpdateCheckManager.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/UpdateCheckManager.java?rev=630977&view=auto
==============================================================================
--- maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/UpdateCheckManager.java (added)
+++ maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/UpdateCheckManager.java Mon Feb 25 12:12:03 2008
@@ -0,0 +1,21 @@
+package org.apache.maven.artifact.manager;
+
+import java.io.File;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
+
+public interface UpdateCheckManager {
+
+	String ROLE = UpdateCheckManager.class.getName();
+
+	boolean isUpdateRequired( Artifact artifact, ArtifactRepository repository );
+
+	void touch( Artifact artifact, ArtifactRepository repository );
+
+    boolean isUpdateRequired( RepositoryMetadata metadata, ArtifactRepository repository, File file );
+
+	void touch( RepositoryMetadata metadata, ArtifactRepository repository, File file );
+
+}

Propchange: maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/UpdateCheckManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/UpdateCheckManager.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Modified: maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/WagonManager.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/WagonManager.java?rev=630977&r1=630976&r2=630977&view=diff
==============================================================================
--- maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/WagonManager.java (original)
+++ maven/artifact/trunk/src/main/java/org/apache/maven/artifact/manager/WagonManager.java Mon Feb 25 12:12:03 2008
@@ -77,7 +77,17 @@
         throws TransferFailedException, ResourceDoesNotExistException;
 
     void getArtifact( Artifact artifact,
+                      List remoteRepositories,
+                      boolean forceUpdateCheck )
+    	throws TransferFailedException, ResourceDoesNotExistException;
+
+    void getArtifact( Artifact artifact,
                       ArtifactRepository repository )
+        throws TransferFailedException, ResourceDoesNotExistException;
+
+    void getArtifact( Artifact artifact,
+                      ArtifactRepository repository,
+                      boolean forceUpdateCheck )
         throws TransferFailedException, ResourceDoesNotExistException;
 
     void putArtifact( File source,

Modified: maven/artifact/trunk/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java?rev=630977&r1=630976&r2=630977&view=diff
==============================================================================
--- maven/artifact/trunk/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java (original)
+++ maven/artifact/trunk/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java Mon Feb 25 12:12:03 2008
@@ -19,6 +19,16 @@
  * under the License.
  */
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.artifact.manager.UpdateCheckManager;
 import org.apache.maven.artifact.manager.WagonManager;
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
 import org.apache.maven.artifact.repository.ArtifactRepository;
@@ -32,16 +42,6 @@
 import org.codehaus.plexus.util.ReaderFactory;
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.Reader;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
 /**
  * @author Jason van Zyl
  * @plexus.component
@@ -53,9 +53,13 @@
     /** @plexus.requirement */
     private WagonManager wagonManager;
 
-    protected DefaultRepositoryMetadataManager( WagonManager wagonManager, Logger logger )
+    /** @plexus.requirement */
+    private UpdateCheckManager updateCheckManager;
+
+    protected DefaultRepositoryMetadataManager( WagonManager wagonManager, UpdateCheckManager updateCheckManager, Logger logger )
     {
         this.wagonManager = wagonManager;
+        this.updateCheckManager = updateCheckManager;
         enableLogging( logger );
     }
 
@@ -68,8 +72,6 @@
                          ArtifactRepository localRepository )
         throws RepositoryMetadataResolutionException
     {
-        MetadataTouchfile touchfile = new MetadataTouchfile( metadata, localRepository );
-
         for ( Iterator i = remoteRepositories.iterator(); i.hasNext(); )
         {
             ArtifactRepository repository = (ArtifactRepository) i.next();
@@ -77,60 +79,42 @@
             ArtifactRepositoryPolicy policy =
                 metadata.isSnapshot() ? repository.getSnapshots() : repository.getReleases();
 
-            if ( !policy.isEnabled() )
-            {
-                getLogger().debug( "Skipping disabled repository " + repository.getId() );
-            }
-            else if ( repository.isBlacklisted() )
-            {
-                getLogger().debug( "Skipping blacklisted repository " + repository.getId() );
-            }
-            else
-            {
-                File file = new File( localRepository.getBasedir(),
-                    localRepository.pathOfLocalRepositoryMetadata( metadata, repository ) );
+            File file = new File( localRepository.getBasedir(),
+                localRepository.pathOfLocalRepositoryMetadata( metadata, repository ) );
 
-                Date lastMod = touchfile.getLastCheckDate( repository.getId(), file.getName(), getLogger() );
-                getLogger().debug( "Got last-check-date of: " + lastMod + "\nfor metadata: " + metadata + "\nwith filename: " + file.getName() + "\nin repository: " + repository.getId() );
-
-                boolean checkForUpdates =
-                    ( lastMod == null ) || policy.checkOutOfDate( lastMod );
-
-                if ( checkForUpdates )
+            if ( updateCheckManager.isUpdateRequired( metadata, repository, file ) )
+            {
+                try
                 {
-                    try
+                    if ( wagonManager.isOnline() )
                     {
-                        if ( wagonManager.isOnline() )
-                        {
-                            getLogger().info(
-                                metadata.getKey() + ": checking for updates from " + repository.getId() );
-                            resolveAlways( metadata, repository, file, policy.getChecksumPolicy(), touchfile );
-                        }
-                        else
-                        {
-                            getLogger().debug( "System is offline. Cannot resolve metadata:\n" +
-                                metadata.extendedToString() + "\n\n" );
-                        }
+                        getLogger().info(
+                            metadata.getKey() + ": checking for updates from " + repository.getId() );
+                        resolveAlways( metadata, repository, file, policy.getChecksumPolicy() );
                     }
-                    catch ( TransferFailedException e )
+                    else
                     {
-                        getLogger().info( "Repository '" + repository.getId() + "' will be blacklisted" );
-                        repository.setBlacklisted( true );
-
-                        // TODO: [jc; 08-Nov-2005] revisit this for 2.1
-                        // suppressing logging to avoid logging this error twice.
+                        getLogger().debug( "System is offline. Cannot resolve metadata:\n" +
+                            metadata.extendedToString() + "\n\n" );
                     }
                 }
-
-                // TODO: should this be inside the above check?
-                // touch file so that this is not checked again until interval has passed
-                if ( file.exists() )
+                catch ( TransferFailedException e )
                 {
-                    file.setLastModified( System.currentTimeMillis() );
+                    getLogger().info( "Repository '" + repository.getId() + "' will be blacklisted" );
+                    repository.setBlacklisted( true );
+
+                    // TODO: [jc; 08-Nov-2005] revisit this for 2.1
+                    // suppressing logging to avoid logging this error twice.
                 }
             }
-        }
 
+            // TODO: should this be inside the above check?
+            // touch file so that this is not checked again until interval has passed
+            if ( file.exists() )
+            {
+                file.setLastModified( System.currentTimeMillis() );
+            }
+        }
         try
         {
             mergeMetadata( metadata, remoteRepositories, localRepository );
@@ -311,9 +295,7 @@
 
         try
         {
-            MetadataTouchfile touchfile = new MetadataTouchfile( metadata, localRepository );
-
-            resolveAlways( metadata, remoteRepository, file, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN, touchfile );
+            resolveAlways( metadata, remoteRepository, file, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN );
         }
         catch ( TransferFailedException e )
         {
@@ -340,8 +322,7 @@
     private void resolveAlways( ArtifactMetadata metadata,
                                 ArtifactRepository repository,
                                 File file,
-                                String checksumPolicy,
-                                MetadataTouchfile touchfile )
+                                String checksumPolicy )
         throws TransferFailedException
     {
         try
@@ -369,7 +350,10 @@
         }
         finally
         {
-            touchfile.touch( repository.getId(), file.getName(), getLogger() );
+            if ( metadata instanceof RepositoryMetadata )
+            {
+                updateCheckManager.touch( (RepositoryMetadata) metadata, repository, file );
+            }
         }
     }
 
@@ -392,9 +376,7 @@
 
         try
         {
-            MetadataTouchfile touchfile = new MetadataTouchfile( metadata, localRepository );
-
-            resolveAlways( metadata, deploymentRepository, file, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN, touchfile );
+            resolveAlways( metadata, deploymentRepository, file, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN );
         }
         catch ( TransferFailedException e )
         {

Modified: maven/artifact/trunk/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java?rev=630977&r1=630976&r2=630977&view=diff
==============================================================================
--- maven/artifact/trunk/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java (original)
+++ maven/artifact/trunk/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java Mon Feb 25 12:12:03 2008
@@ -19,13 +19,21 @@
  * under the License.
  */
 
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.factory.ArtifactFactory;
 import org.apache.maven.artifact.manager.WagonManager;
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
 import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
 import org.apache.maven.artifact.repository.metadata.Metadata;
 import org.apache.maven.artifact.repository.metadata.Snapshot;
 import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
@@ -37,16 +45,6 @@
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 import org.codehaus.plexus.util.FileUtils;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 /**
  * @author Jason van Zyl
  * @plexus.component
@@ -155,92 +153,40 @@
                 remoteRepositories,
                 localRepository );
 
-            boolean localCopy = false;
-
-            for ( Iterator i = artifact.getMetadataList().iterator(); i.hasNext(); )
-            {
-                ArtifactMetadata m = (ArtifactMetadata) i.next();
-
-                if ( m instanceof SnapshotArtifactRepositoryMetadata )
-                {
-                    SnapshotArtifactRepositoryMetadata snapshotMetadata = (SnapshotArtifactRepositoryMetadata) m;
-
-                    Metadata metadata = snapshotMetadata.getMetadata();
-
-                    if ( metadata != null )
-                    {
-                        Versioning versioning = metadata.getVersioning();
-
-                        if ( versioning != null )
-                        {
-                            Snapshot snapshot = versioning.getSnapshot();
-
-                            if ( snapshot != null )
-                            {
-                                localCopy = snapshot.isLocalCopy();
-                            }
-                        }
-                    }
-                }
-            }
+            boolean localCopy = isLocalCopy( artifact );
 
             File destination = artifact.getFile();
 
-            List repositories = remoteRepositories;
-
-            // TODO: would prefer the snapshot transformation took care of this. Maybe we need a "shouldresolve" flag.
-            if ( artifact.isSnapshot() && artifact.getBaseVersion().equals( artifact.getVersion() ) &&
-                destination.exists() && !localCopy )
-            {
-                Date comparisonDate = new Date( destination.lastModified() );
-
-                // cull to list of repositories that would like an update
-                repositories = new ArrayList( remoteRepositories );
-                for ( Iterator i = repositories.iterator(); i.hasNext(); )
-                {
-                    ArtifactRepository repository = (ArtifactRepository) i.next();
-
-                    ArtifactRepositoryPolicy policy = repository.getSnapshots();
-
-                    if ( !policy.isEnabled() || !policy.checkOutOfDate( comparisonDate ) )
-                    {
-                        i.remove();
-                    }
-                }
-
-                if ( !repositories.isEmpty() )
-                {
-                    // someone wants to check for updates
-                    force = true;
-                }
-            }
             boolean resolved = false;
-            if ( !destination.exists() || force )
+            if ( !wagonManager.isOnline() )
             {
-                if ( !wagonManager.isOnline() )
+                if ( !destination.exists() )
                 {
                     throw new ArtifactNotFoundException(
                         "System is offline.",
                         artifact );
                 }
-
+            }
+            else if ( !artifact.isSnapshot() || !localCopy || force )
+            {
                 try
                 {
-                    // TODO: force should be passed to the wagon manager
                     if ( artifact.getRepository() != null )
                     {
                         // the transformations discovered the artifact - so use it exclusively
                         wagonManager.getArtifact(
                             artifact,
-                            artifact.getRepository() );
+                            artifact.getRepository(),
+                            force );
                     }
                     else
                     {
                         wagonManager.getArtifact(
                             artifact,
-                            repositories );
+                            remoteRepositories,
+                            force );
                     }
-
+    
                     if ( !artifact.isResolved() && !destination.exists() )
                     {
                         throw new ArtifactResolutionException(
@@ -265,10 +211,11 @@
                         remoteRepositories,
                         e );
                 }
-
+    
                 resolved = true;
             }
-            else if ( destination.exists() )
+
+            if ( destination.exists() )
             {
                 // locally resolved...no need to hit the remote repo.
                 artifact.setResolved( true );
@@ -310,7 +257,43 @@
         }
     }
 
-    public ArtifactResolutionResult resolveTransitively( Set artifacts,
+	private boolean isLocalCopy( Artifact artifact ) 
+	{
+
+		boolean localCopy = false;
+
+        for ( Iterator i = artifact.getMetadataList().iterator(); i.hasNext(); )
+        {
+            ArtifactMetadata m = (ArtifactMetadata) i.next();
+
+            if ( m instanceof SnapshotArtifactRepositoryMetadata )
+            {
+                SnapshotArtifactRepositoryMetadata snapshotMetadata = (SnapshotArtifactRepositoryMetadata) m;
+
+                Metadata metadata = snapshotMetadata.getMetadata();
+
+                if ( metadata != null )
+                {
+                    Versioning versioning = metadata.getVersioning();
+
+                    if ( versioning != null )
+                    {
+                        Snapshot snapshot = versioning.getSnapshot();
+
+                        if ( snapshot != null )
+                        {
+                            // TODO is it possible to have more than one SnapshotArtifactRepositoryMetadata
+                            localCopy = snapshot.isLocalCopy();
+                        }
+                    }
+                }
+            }
+        }
+
+        return localCopy;
+    }
+
+	public ArtifactResolutionResult resolveTransitively( Set artifacts,
                                                          Artifact originatingArtifact,
                                                          ArtifactRepository localRepository,
                                                          List remoteRepositories,

Added: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManagerTest.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManagerTest.java?rev=630977&view=auto
==============================================================================
--- maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManagerTest.java (added)
+++ maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManagerTest.java Mon Feb 25 12:12:03 2008
@@ -0,0 +1,138 @@
+package org.apache.maven.artifact.manager;
+
+import java.io.File;
+
+import org.apache.maven.artifact.AbstractArtifactComponentTestCase;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
+import org.codehaus.plexus.logging.Logger;
+import org.codehaus.plexus.logging.console.ConsoleLogger;
+
+public class DefaultUpdateCheckManagerTest
+    extends AbstractArtifactComponentTestCase
+{
+
+    DefaultUpdateCheckManager updateCheckManager;
+
+    @Override
+    protected String component()
+    {
+        return "updateCheckManager";
+    }
+
+    @Override
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        updateCheckManager = new DefaultUpdateCheckManager( new ConsoleLogger( Logger.LEVEL_DEBUG, "test" ) );
+    }
+
+    public void testArtifact() throws Exception
+    {
+        ArtifactRepository remoteRepository = remoteRepository();
+
+        ArtifactRepository localRepository = localRepository();
+
+        Artifact a = createArtifact( "a", "0.0.1-SNAPSHOT" );
+        File file = new File( localRepository.getBasedir(), 
+                              localRepository.pathOf( a ) );
+        file.delete();
+        a.setFile( file );
+
+        File touchFile = new File ( file.getParent(), DefaultUpdateCheckManager.TOUCHFILE_NAME );
+        touchFile.delete();
+
+        assertTrue( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+
+        file.getParentFile().mkdirs();
+        file.createNewFile();
+        updateCheckManager.touch( a, remoteRepository );
+
+        assertFalse( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+
+        assertNull( updateCheckManager.getLastModifiedFromTouchfile( file ) );
+    }
+
+    public void testMissingArtifact()
+        throws Exception
+    {
+        ArtifactRepository remoteRepository = remoteRepository();
+
+        ArtifactRepository localRepository = localRepository();
+
+        Artifact a = createArtifact( "a", "0.0.1-SNAPSHOT" );
+        File file = new File( localRepository.getBasedir(), 
+                              localRepository.pathOf( a ) );
+        file.delete();
+        a.setFile( file );
+
+        File touchFile = new File ( file.getParent(), DefaultUpdateCheckManager.TOUCHFILE_NAME );
+        touchFile.delete();
+
+        assertTrue( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+
+        updateCheckManager.touch( a, remoteRepository );
+
+        assertFalse( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+
+        assertFalse( file.exists() );
+        assertNotNull( updateCheckManager.getLastModifiedFromTouchfile( file ) );
+    }
+
+    public void testMetadata() throws Exception
+    {
+        ArtifactRepository remoteRepository = remoteRepository();
+
+        ArtifactRepository localRepository = localRepository();
+
+        Artifact a = createRemoteArtifact( "a", "0.0.1-SNAPSHOT" );
+        RepositoryMetadata metadata = new ArtifactRepositoryMetadata( a );
+
+        File file = new File( localRepository.getBasedir(),
+                              localRepository.pathOfLocalRepositoryMetadata( metadata, localRepository ) );
+        file.delete();
+
+        File touchFile = new File ( file.getParent(), DefaultUpdateCheckManager.TOUCHFILE_NAME );
+        touchFile.delete();
+
+        assertTrue( updateCheckManager.isUpdateRequired( metadata, remoteRepository, file ) );
+
+        file.getParentFile().mkdirs();
+        file.createNewFile();
+        updateCheckManager.touch( metadata, remoteRepository, file );
+
+        assertFalse( updateCheckManager.isUpdateRequired( metadata, remoteRepository, file ) );
+
+        assertNotNull( updateCheckManager.getLastModifiedFromTouchfile( file ) );
+    }
+
+    public void testMissingMetadata() throws Exception
+    {
+        ArtifactRepository remoteRepository = remoteRepository();
+
+        ArtifactRepository localRepository = localRepository();
+
+        Artifact a = createRemoteArtifact( "a", "0.0.1-SNAPSHOT" );
+        RepositoryMetadata metadata = new ArtifactRepositoryMetadata( a );
+
+        File file = new File( localRepository.getBasedir(),
+                              localRepository.pathOfLocalRepositoryMetadata( metadata, localRepository ) );
+        file.delete();
+
+        File touchFile = new File ( file.getParent(), DefaultUpdateCheckManager.TOUCHFILE_NAME );
+        touchFile.delete();
+
+        assertTrue( updateCheckManager.isUpdateRequired( metadata, remoteRepository, file ) );
+
+        updateCheckManager.touch( metadata, remoteRepository, file );
+
+        assertFalse( updateCheckManager.isUpdateRequired( metadata, remoteRepository, file ) );
+
+        assertNotNull( updateCheckManager.getLastModifiedFromTouchfile( file ) );
+    }
+
+}

Propchange: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManagerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/DefaultUpdateCheckManagerTest.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Modified: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/WagonNoOp.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/WagonNoOp.java?rev=630977&r1=630976&r2=630977&view=diff
==============================================================================
--- maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/WagonNoOp.java (original)
+++ maven/artifact/trunk/src/test/java/org/apache/maven/artifact/manager/WagonNoOp.java Mon Feb 25 12:12:03 2008
@@ -20,6 +20,7 @@
  */
 
 import java.io.File;
+import java.io.IOException;
 
 import org.apache.maven.wagon.AbstractWagon;
 import org.apache.maven.wagon.ResourceDoesNotExistException;
@@ -42,14 +43,29 @@
         Resource resource = new Resource( resourceName );
         fireGetInitiated( resource, destination );
         fireGetStarted( resource, destination );
+        try
+        {
+            destination.createNewFile();
+        }
+        catch ( IOException e )
+        {
+            // ignored
+        }
         fireGetCompleted( resource, destination );
     }
 
     public boolean getIfNewer( String resourceName, File destination, long timestamp )
         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
     {
-        // NO-OP
-        return false;
+        try
+        {
+            destination.createNewFile();
+        }
+        catch ( IOException e )
+        {
+            return false;
+        }
+        return true;
     }
 
     public void openConnection()

Modified: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManagerTest.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/test/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManagerTest.java?rev=630977&r1=630976&r2=630977&view=diff
==============================================================================
--- maven/artifact/trunk/src/test/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManagerTest.java (original)
+++ maven/artifact/trunk/src/test/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManagerTest.java Mon Feb 25 12:12:03 2008
@@ -1,5 +1,14 @@
 package org.apache.maven.artifact.repository.metadata;
 
+import java.io.File;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import org.apache.maven.artifact.manager.DefaultUpdateCheckManager;
 import org.apache.maven.artifact.manager.WagonManager;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
@@ -12,14 +21,6 @@
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 import org.easymock.MockControl;
 
-import java.io.File;
-import java.io.IOException;
-import java.text.ParseException;
-import java.util.Collections;
-import java.util.Date;
-
-import junit.framework.TestCase;
-
 public class DefaultRepositoryMetadataManagerTest
     extends TestCase
 {
@@ -34,6 +35,8 @@
 
     private WagonManager wagonManager;
 
+	private DefaultUpdateCheckManager updateCheckManager;
+
     @Override
     public void setUp()
         throws Exception
@@ -44,6 +47,8 @@
         mockManager.add( wagonManagerCtl );
 
         wagonManager = (WagonManager) wagonManagerCtl.getMock();
+        
+        updateCheckManager = new DefaultUpdateCheckManager( new ConsoleLogger( Logger.LEVEL_DEBUG, "test" ) );
     }
 
     @Override
@@ -124,17 +129,16 @@
 
         Logger logger = new ConsoleLogger( Logger.LEVEL_DEBUG, "test" );
 
-        new DefaultRepositoryMetadataManager( wagonManager, logger ).resolveAlways( metadata,
-                                                                                    localRepo,
-                                                                                    localRepo );
+        new DefaultRepositoryMetadataManager( wagonManager, updateCheckManager, logger ).resolveAlways( metadata,
+                                                                                                       localRepo,
+                                                                                                       localRepo );
 
         // helps the lastUpdate interval be significantly different.
         Thread.sleep( 1000 );
 
         Date end = new Date();
 
-        MetadataTouchfile touchfile = new MetadataTouchfile( metadata, localRepo );
-        Date checkDate = touchfile.getLastCheckDate( localRepo.getId(), filename, logger );
+        Date checkDate = updateCheckManager.getLastModifiedFromTouchfile( new File( dir, path ) );
 
         assertNotNull( checkDate );
         assertTrue( checkDate.after( start ) );
@@ -215,17 +219,16 @@
 
         Logger logger = new ConsoleLogger( Logger.LEVEL_DEBUG, "test" );
 
-        new DefaultRepositoryMetadataManager( wagonManager, logger ).resolveAlways( metadata,
-                                                                                    localRepo,
-                                                                                    localRepo );
+        new DefaultRepositoryMetadataManager( wagonManager, updateCheckManager, logger ).resolveAlways( metadata,
+                                                                                                        localRepo,
+                                                                                                        localRepo );
 
         // helps the lastUpdate interval be significantly different.
         Thread.sleep( 1000 );
 
         Date end = new Date();
 
-        MetadataTouchfile touchfile = new MetadataTouchfile( metadata, localRepo );
-        Date checkDate = touchfile.getLastCheckDate( localRepo.getId(), filename, logger );
+        Date checkDate = updateCheckManager.getLastModifiedFromTouchfile( new File( dir, path ) );
 
         assertNotNull( checkDate );
         assertTrue( checkDate.after( start ) );
@@ -303,17 +306,16 @@
 
         Logger logger = new ConsoleLogger( Logger.LEVEL_DEBUG, "test" );
 
-        new DefaultRepositoryMetadataManager( wagonManager, logger ).resolveAlways( metadata,
-                                                                                    localRepo,
-                                                                                    localRepo );
+        new DefaultRepositoryMetadataManager( wagonManager, updateCheckManager, logger ).resolveAlways( metadata,
+                                                                                                        localRepo,
+                                                                                                        localRepo );
 
         // helps the lastUpdate interval be significantly different.
         Thread.sleep( 1000 );
 
         Date end = new Date();
 
-        MetadataTouchfile touchfile = new MetadataTouchfile( metadata, localRepo );
-        Date checkDate = touchfile.getLastCheckDate( localRepo.getId(), filename, logger );
+        Date checkDate = updateCheckManager.getLastModifiedFromTouchfile( new File( dir, path ) );
 
         assertNotNull( checkDate );
         assertTrue( checkDate.after( start ) );
@@ -421,17 +423,16 @@
 
         System.out.println( "Testing re-check proofing..." );
 
-        RepositoryMetadataManager mgr = new DefaultRepositoryMetadataManager( wagonManager, logger );
+        RepositoryMetadataManager mgr = new DefaultRepositoryMetadataManager( wagonManager, updateCheckManager, logger );
         mgr.resolve( metadata, Collections.singletonList( remoteRepo ), localRepo );
 
-        MetadataTouchfile touchfile = new MetadataTouchfile( metadata, localRepo );
-        Date checkDate = touchfile.getLastCheckDate( repoId, filename, logger );
+        Date checkDate = updateCheckManager.getLastModifiedFromTouchfile( new File( dir, path ) );
 
         assertNotNull( checkDate );
 
         mgr.resolve( metadata, Collections.singletonList( remoteRepo ), localRepo );
 
-        checkDate = touchfile.getLastCheckDate( repoId, filename, logger );
+        checkDate = updateCheckManager.getLastModifiedFromTouchfile( new File( dir, path ) );
 
         assertNotNull( checkDate );
 

Added: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.java?rev=630977&view=auto
==============================================================================
--- maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.java (added)
+++ maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.java Mon Feb 25 12:12:03 2008
@@ -0,0 +1,361 @@
+package org.apache.maven.artifact.resolver;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.util.List;
+
+import org.apache.maven.artifact.AbstractArtifactComponentTestCase;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.manager.WagonManager;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.apache.maven.artifact.repository.DefaultArtifactRepository;
+import org.apache.maven.artifact.repository.metadata.Metadata;
+import org.apache.maven.artifact.repository.metadata.Snapshot;
+import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
+import org.apache.maven.artifact.repository.metadata.Versioning;
+import org.codehaus.plexus.util.FileUtils;
+
+public class ArtifactUpdatePolicyTest
+    extends AbstractArtifactComponentTestCase
+{
+
+    private static final long TWO_SECONDS = 2 * 1000L;
+    
+    private static final long TWO_DAYS = 2 * 86400L * 1000L;
+
+    private ArtifactResolver artifactResolver;
+
+    private List remoteRepositories;
+
+    private WagonManager wagonManager;
+
+    private TestTransferListener listener;
+
+    private ArtifactRepository localRepository;
+
+    private DefaultArtifactRepository remoteRepository;
+
+    protected String component()
+    {
+        return "artifact-update-policy";
+    }
+
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        artifactResolver = (ArtifactResolver) lookup( ArtifactResolver.ROLE );
+
+        remoteRepositories = remoteRepositories();
+        remoteRepository = (DefaultArtifactRepository) remoteRepositories.get( 0 );
+        remoteRepository.setProtocol( "testfile" );
+        remoteRepository.getSnapshots().setChecksumPolicy( ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE );
+        remoteRepository.getReleases().setChecksumPolicy( ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE );
+        FileUtils.deleteDirectory( new File( remoteRepository.getBasedir() ) );
+
+        wagonManager = (WagonManager) lookup( WagonManager.ROLE );
+        listener = new TestTransferListener();
+        wagonManager.setDownloadMonitor( listener );
+
+        localRepository = localRepository();
+        FileUtils.deleteDirectory( new File( localRepository.getBasedir() ) );
+    }
+
+    protected void tearDown()
+        throws Exception
+    {
+        wagonManager.setDownloadMonitor( null );
+        wagonManager.setOnline( true );
+        super.tearDown();
+    }
+
+
+    private void assertTransfers( String[] expected )
+    {
+        StringBuffer expectedSB = new StringBuffer();
+        for ( int i = 0; i < expected.length; i++ )
+        {
+            expectedSB.append( expected[ i ] ).append( "\n" );
+        }
+
+        List actual = listener.getTransfers();
+        StringBuffer actualSB = new StringBuffer();
+        for ( int i = 0; i < actual.size(); i++ )
+        {
+            actualSB.append( actual.get( i ) ).append( "\n" );
+        }
+
+        assertEquals( expectedSB.toString(), actualSB.toString() );
+    }
+
+    private void deleteFromLocalRepository( Artifact o )
+    {
+        File file = new File( localRepository.getBasedir(), localRepository.pathOf( o ) );
+        file.delete();
+    }
+
+
+    private Artifact createLocalCopy( String artifactId, String version ) throws Exception
+    {
+        Artifact a = createArtifact( artifactId, version );
+
+        createArtifact( a, localRepository );
+
+        SnapshotArtifactRepositoryMetadata snapshotMetadata = new SnapshotArtifactRepositoryMetadata( a );
+        Metadata metadata = new Metadata();
+        Versioning versioning = new Versioning();
+        Snapshot snapshot = new Snapshot();
+        snapshot.setLocalCopy( true );
+        versioning.setSnapshot( snapshot );
+        metadata.setVersioning( versioning );
+        snapshotMetadata.setMetadata( metadata );
+        a.addMetadata( snapshotMetadata );
+        
+        return a;
+    }
+
+    public void testForceLocalDoesNotExist()
+        throws Exception
+    {
+        Artifact a = createRemoteArtifact( "o", "0.0.1-SNAPSHOT" );
+
+        artifactResolver.resolveAlways( a, remoteRepositories, localRepository );
+
+        assertTransfers( new String[] { 
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar",
+            "getTransfer org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar",
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar.sha1", 
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar.md5" } );
+    }
+
+    public void testForceButNoNewUpdates() throws Exception
+    {
+        Artifact a = createRemoteArtifact( "o", "0.0.1-SNAPSHOT" );
+        createArtifact( a, localRepository );
+
+        artifactResolver.resolveAlways( a, remoteRepositories, localRepository );
+
+        assertTransfers( new String[] { 
+            "getIfNewer org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar" } );
+    }
+
+    public void testForceNewUpdate() throws Exception
+    {
+        Artifact a = createRemoteArtifact( "o", "0.0.1-SNAPSHOT" );
+        createArtifact( a, localRepository );
+        setLastModified( a, System.currentTimeMillis() - 2000L, localRepository );
+
+        artifactResolver.resolveAlways( a, remoteRepositories, localRepository );
+
+        assertTransfers( new String[] { 
+            "getIfNewer org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar",
+            "getTransfer org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar",
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar.sha1", 
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar.md5" } );
+    }
+
+    public void testForceUpdateMissing() throws Exception
+    {
+        Artifact a = createArtifact( "o", "0.0.1-SNAPSHOT" );
+
+        try
+        {
+            artifactResolver.resolveAlways( a, remoteRepositories, localRepository );
+            fail( "Expected missing artifact" );
+        }
+        catch ( ArtifactNotFoundException expected )
+        {
+            // expected
+        }
+
+        try
+        {
+            artifactResolver.resolveAlways( a, remoteRepositories, localRepository );
+            fail( "Expected missing artifact" );
+        }
+        catch ( ArtifactNotFoundException expected )
+        {
+            // expected
+        }
+
+        assertTransfers( new String[] { 
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar",
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar" } );
+        
+    }
+
+    public void testSnapshotUpdate() throws Exception
+    {
+        Artifact a = createRemoteArtifact( "o", "0.0.1-SNAPSHOT" );
+        createArtifact( a, localRepository );
+        setLastModified( a, System.currentTimeMillis() - TWO_DAYS, localRepository );
+
+        artifactResolver.resolve( a, remoteRepositories, localRepository );
+
+        assertTransfers( new String[] { 
+            "getIfNewer org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar",
+            "getTransfer org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar",
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar.sha1", 
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar.md5" } );
+    }
+
+    public void testSnapshotNoUpdates() throws Exception
+    {
+        Artifact a = createRemoteArtifact( "o", "0.0.1-SNAPSHOT" );
+        createArtifact( a, localRepository );
+        long timestamp = System.currentTimeMillis() - TWO_DAYS;
+        setLastModified( a, timestamp, localRepository );
+        setLastModified( a, timestamp, remoteRepository );
+
+        artifactResolver.resolve( a, remoteRepositories, localRepository );
+
+        assertTransfers( new String[] { 
+            "getIfNewer org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar" } );
+    }
+
+    public void testSnapshotPolicyCheck() throws Exception
+    {
+        Artifact a = createRemoteArtifact( "o", "0.0.1-SNAPSHOT" );
+        createArtifact( a, localRepository );
+        long timestamp = System.currentTimeMillis() - TWO_SECONDS;
+        setLastModified( a, timestamp, localRepository );
+        setLastModified( a, timestamp, remoteRepository );
+
+        artifactResolver.resolve( a, remoteRepositories, localRepository );
+
+        assertTransfers( new String[] { } );
+    }
+
+    public void testLocalCopy() throws Exception
+    {
+        Artifact a = createRemoteArtifact( "o", "0.0.1-SNAPSHOT" );
+        a = createLocalCopy( a.getArtifactId(), a.getVersion() );
+        long timestamp = System.currentTimeMillis() - TWO_DAYS;
+        setLastModified( a, timestamp, localRepository );
+
+        artifactResolver.resolve( a, remoteRepositories, localRepository );
+
+        assertTransfers( new String[] { } );
+    }
+
+    public void testForceUpdateLocalCopy() throws Exception
+    {
+        Artifact a = createRemoteArtifact( "o", "0.0.1-SNAPSHOT" );
+        a = createLocalCopy( a.getArtifactId(), a.getVersion() );
+        long timestamp = System.currentTimeMillis() - TWO_SECONDS;
+        setLastModified( a, timestamp, localRepository );
+
+        artifactResolver.resolveAlways( a, remoteRepositories, localRepository );
+
+        assertTransfers( new String[] { 
+            "getIfNewer org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar",
+            "getTransfer org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar",
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar.sha1", 
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar.md5" } );
+    }
+
+    private void setLastModified( Artifact a, long timestamp, ArtifactRepository repository )
+    {
+        File file = new File ( repository.getBasedir(),
+                               repository.pathOf( a ) );
+        file.setLastModified( timestamp );
+    }
+
+    public void testSnapshotUpdatePolicyForMissingArtifacts()
+        throws Exception
+    {
+        Artifact j = createArtifact( "o", "0.0.1-SNAPSHOT" );
+
+        try
+        {
+            artifactResolver.resolve( j, remoteRepositories, localRepository );
+            fail( "Expected missing artifact" );
+        }
+        catch ( ArtifactNotFoundException expected )
+        {
+            // expected
+        }
+
+        try
+        {
+            artifactResolver.resolve( j, remoteRepositories, localRepository );
+            fail( "Expected missing artifact" );
+        }
+        catch ( ArtifactNotFoundException expected )
+        {
+            // expected
+        }
+
+        assertTransfers( new String[] { 
+            "get org.apache.maven/jars/o-0.0.1-SNAPSHOT.jar" } );
+    }
+
+    public void testResolutionOfArtifactsDeletedFromLocalRepo()
+        throws Exception
+    {
+        Artifact j = createRemoteArtifact( "j", "0.0.1-SNAPSHOT" );
+
+        artifactResolver.resolve( j, remoteRepositories, localRepository() );
+
+        // sanity check
+        assertTrue( j.isResolved() );
+        assertTrue( j.getFile().canRead() );
+
+        j.getFile().delete();
+
+        j = createArtifact( j.getArtifactId(), j.getVersion() );
+        artifactResolver.resolve( j, remoteRepositories, localRepository() );
+
+        assertTrue( j.isResolved() );
+        assertTrue( j.getFile().canRead() );
+    }
+
+    public void testReleaseUpdate()
+        throws Exception
+    {
+        Artifact a = createRemoteArtifact( "o", "1.0.1" );
+        createArtifact( a, localRepository );
+        setLastModified( a, System.currentTimeMillis() - TWO_DAYS, localRepository );
+
+        artifactResolver.resolve( a, remoteRepositories, localRepository );
+
+        assertTransfers( new String[] { 
+            "getIfNewer org.apache.maven/jars/o-1.0.1.jar",
+            "getTransfer org.apache.maven/jars/o-1.0.1.jar",
+            "get org.apache.maven/jars/o-1.0.1.jar.sha1", 
+            "get org.apache.maven/jars/o-1.0.1.jar.md5" } );
+    }
+
+    public void testResolveExistingLocalArtifactInOfflineMode()
+        throws Exception
+    {
+        Artifact a = createLocalArtifact( "a", "1.0.0" );
+
+        wagonManager.setOnline( false );
+
+        artifactResolver.resolve( a, remoteRepositories(), localRepository() );
+
+        assertTrue( a.isResolved() );
+    }
+
+}

Propchange: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestFileWagon.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestFileWagon.java?rev=630977&view=auto
==============================================================================
--- maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestFileWagon.java (added)
+++ maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestFileWagon.java Mon Feb 25 12:12:03 2008
@@ -0,0 +1,82 @@
+package org.apache.maven.artifact.resolver;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.InputStream;
+
+import org.apache.maven.wagon.ResourceDoesNotExistException;
+import org.apache.maven.wagon.TransferFailedException;
+import org.apache.maven.wagon.authorization.AuthorizationException;
+import org.apache.maven.wagon.events.TransferListener;
+import org.apache.maven.wagon.providers.file.FileWagon;
+import org.apache.maven.wagon.resource.Resource;
+
+public class TestFileWagon
+    extends FileWagon
+{
+    private TestTransferListener testTransferListener;
+
+    protected void getTransfer( Resource resource, 
+                                File destination, 
+                                InputStream input, 
+                                boolean closeInput, 
+                                int maxSize )
+        throws TransferFailedException
+    {
+        addTransfer( "getTransfer " + resource.getName() );
+        super.getTransfer( resource, destination, input, closeInput, maxSize );
+    }
+
+    public void get( String resourceName, File destination )
+        throws TransferFailedException, 
+               ResourceDoesNotExistException, 
+               AuthorizationException
+    {
+        addTransfer( "get " + resourceName );
+        super.get( resourceName, destination );
+    }
+
+    private void addTransfer( String resourceName )
+    {
+        if ( testTransferListener != null )
+        {
+            testTransferListener.addTransfer( resourceName );
+        }
+    }
+
+    public boolean getIfNewer( String resourceName, File destination, long timestamp )
+        throws TransferFailedException, 
+               ResourceDoesNotExistException, 
+               AuthorizationException
+    {
+        addTransfer( "getIfNewer " + resourceName );
+        return super.getIfNewer( resourceName, destination, timestamp );
+    }
+
+    public void addTransferListener( TransferListener listener )
+    {
+        if ( listener instanceof TestTransferListener )
+        {
+            testTransferListener = (TestTransferListener) listener;
+        }
+        super.addTransferListener( listener );
+    }
+}

Propchange: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestFileWagon.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestFileWagon.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestTransferListener.java
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestTransferListener.java?rev=630977&view=auto
==============================================================================
--- maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestTransferListener.java (added)
+++ maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestTransferListener.java Mon Feb 25 12:12:03 2008
@@ -0,0 +1,43 @@
+package org.apache.maven.artifact.resolver;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.maven.wagon.observers.AbstractTransferListener;
+
+public class TestTransferListener
+    extends AbstractTransferListener
+{
+
+    private final List transfers = new ArrayList();
+
+    public List getTransfers()
+    {
+        return transfers;
+    }
+
+    public void addTransfer( String name )
+    {
+        transfers.add( name );
+    }
+
+}

Propchange: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestTransferListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/artifact/trunk/src/test/java/org/apache/maven/artifact/resolver/TestTransferListener.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: maven/artifact/trunk/src/test/resources/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.xml
URL: http://svn.apache.org/viewvc/maven/artifact/trunk/src/test/resources/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.xml?rev=630977&view=auto
==============================================================================
--- maven/artifact/trunk/src/test/resources/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.xml (added)
+++ maven/artifact/trunk/src/test/resources/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.xml Mon Feb 25 12:12:03 2008
@@ -0,0 +1,29 @@
+<!--
+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.
+-->
+
+<plexus>
+  <components>
+    <component>
+      <role>org.apache.maven.wagon.Wagon</role>
+      <role-hint>testfile</role-hint>
+      <implementation>org.apache.maven.artifact.resolver.TestFileWagon</implementation>
+      <instantiation-strategy>per-lookup</instantiation-strategy>
+    </component>
+  </components>
+</plexus>
\ No newline at end of file

Propchange: maven/artifact/trunk/src/test/resources/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/artifact/trunk/src/test/resources/org/apache/maven/artifact/resolver/ArtifactUpdatePolicyTest.xml
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"