You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by xa...@apache.org on 2008/01/10 22:28:32 UTC

svn commit: r610936 - in /ant/ivy/core/trunk: ./ src/java/org/apache/ivy/core/cache/ src/java/org/apache/ivy/core/resolve/ src/java/org/apache/ivy/plugins/resolver/ test/java/org/apache/ivy/core/resolve/

Author: xavier
Date: Thu Jan 10 13:28:31 2008
New Revision: 610936

URL: http://svn.apache.org/viewvc?rev=610936&view=rev
Log:
NEW: Cache dynamic revision resolution (IVY-694)
TODO:
- check if this should be the default or not, and add easier way to change the default TTL
- add unit test for TTL
- update doc
- add more flexible ttl settings?

Modified:
    ant/ivy/core/trunk/CHANGES.txt
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/CacheMetadataOptions.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/RepositoryCacheManager.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolveEngine.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolveOptions.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/BasicResolver.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/CacheResolver.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java
    ant/ivy/core/trunk/test/java/org/apache/ivy/core/resolve/ResolveTest.java

Modified: ant/ivy/core/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/CHANGES.txt?rev=610936&r1=610935&r2=610936&view=diff
==============================================================================
--- ant/ivy/core/trunk/CHANGES.txt (original)
+++ ant/ivy/core/trunk/CHANGES.txt Thu Jan 10 13:28:31 2008
@@ -62,6 +62,7 @@
 - NEW: Introduce RepositoryManagementEngine (IVY-665 - not completed yet)
 - NEW: Add support for importing environment variables (IVY-608)
 - NEW: Add ability for buildlist task to start build from specified module in the list (IVY-697) (thanks to Mirko Bulovic)
+- NEW: Cache dynamic revision resolution (IVY-694)
 
 - IMPROVEMENT: Make IBiblio resolver compatible with maven proxy (IVY-466)
 - IMPROVEMENT: Use namespace aware validation (IVY-553)

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/CacheMetadataOptions.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/CacheMetadataOptions.java?rev=610936&r1=610935&r2=610936&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/CacheMetadataOptions.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/CacheMetadataOptions.java Thu Jan 10 13:28:31 2008
@@ -20,18 +20,12 @@
 import org.apache.ivy.plugins.namespace.Namespace;
 
 public class CacheMetadataOptions extends CacheDownloadOptions {
-    private boolean isChanging = false; 
-    private boolean isCheckmodified = false;
-    private boolean validate = false; 
+    private boolean validate = false;
     private Namespace namespace = Namespace.SYSTEM_NAMESPACE;
+    private Boolean isCheckmodified = null;
+    private String changingMatcherName = null;
+    private String changingPattern = null;
     
-    public boolean isChanging() {
-        return isChanging;
-    }
-    public CacheMetadataOptions setChanging(boolean isChanging) {
-        this.isChanging = isChanging;
-        return this;
-    }
     public Namespace getNamespace() {
         return namespace;
     }
@@ -46,11 +40,25 @@
         this.validate = validate;
         return this;
     }
-    public boolean isCheckmodified() {
+    public Boolean isCheckmodified() {
         return isCheckmodified;
     }
-    public CacheMetadataOptions setCheckmodified(boolean isCheckmodified) {
+    public CacheMetadataOptions setCheckmodified(Boolean isCheckmodified) {
         this.isCheckmodified = isCheckmodified;
+        return this;
+    }
+    public String getChangingMatcherName() {
+        return changingMatcherName;
+    }
+    public CacheMetadataOptions setChangingMatcherName(String changingMatcherName) {
+        this.changingMatcherName = changingMatcherName;
+        return this;
+    }
+    public String getChangingPattern() {
+        return changingPattern;
+    }
+    public CacheMetadataOptions setChangingPattern(String changingPattern) {
+        this.changingPattern  = changingPattern;
         return this;
     }
 }

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java?rev=610936&r1=610935&r2=610936&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java Thu Jan 10 13:28:31 2008
@@ -27,6 +27,7 @@
 import org.apache.ivy.core.IvyPatternHelper;
 import org.apache.ivy.core.module.descriptor.Artifact;
 import org.apache.ivy.core.module.descriptor.DefaultArtifact;
+import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
 import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
 import org.apache.ivy.core.module.id.ModuleRevisionId;
 import org.apache.ivy.core.report.ArtifactDownloadReport;
@@ -36,6 +37,9 @@
 import org.apache.ivy.core.settings.IvySettings;
 import org.apache.ivy.plugins.IvySettingsAware;
 import org.apache.ivy.plugins.lock.LockStrategy;
+import org.apache.ivy.plugins.matcher.Matcher;
+import org.apache.ivy.plugins.matcher.NoMatcher;
+import org.apache.ivy.plugins.matcher.PatternMatcher;
 import org.apache.ivy.plugins.namespace.NameSpaceHelper;
 import org.apache.ivy.plugins.parser.ModuleDescriptorParser;
 import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry;
@@ -58,6 +62,9 @@
 
     private static final String DEFAULT_IVY_PATTERN = 
         "[organisation]/[module]/ivy-[revision].xml";
+    
+    // default TTL for resolved revisions is one hour
+    private static final long DEFAULT_TTL = 1000 * 60 * 60 * 1; 
 
     private IvySettings settings;
     
@@ -75,6 +82,14 @@
 
     private String lockStrategyName; 
 
+    private String changingPattern;
+
+    private String changingMatcherName = PatternMatcher.EXACT_OR_REGEXP;
+
+    private Boolean checkmodified;
+
+    private long defaultTTL = DEFAULT_TTL;
+
     public DefaultRepositoryCacheManager() {
     }
 
@@ -136,6 +151,14 @@
     public void setBasedir(File cache) {
         this.basedir = cache;
     }
+    
+    public long getDefaultTTL() {
+        return defaultTTL;
+    }
+    
+    public void setDefaultTTL(long defaultTTL) {
+        this.defaultTTL = defaultTTL;
+    }
 
     public String getDataFilePattern() {
         return dataFilePattern;
@@ -157,6 +180,45 @@
         this.name = name;
     }
 
+    public String getChangingMatcherName() {
+        return changingMatcherName;
+    }
+
+    public void setChangingMatcher(String changingMatcherName) {
+        this.changingMatcherName = changingMatcherName;
+    }
+
+    public String getChangingPattern() {
+        return changingPattern;
+    }
+
+    public void setChangingPattern(String changingPattern) {
+        this.changingPattern = changingPattern;
+    }
+
+
+    /**
+     * True if this resolver should check lastmodified date to know if ivy files are up to date.
+     * 
+     * @return
+     */
+    public boolean isCheckmodified() {
+        if (checkmodified == null) {
+            if (getSettings() != null) {
+                String check = getSettings().getVariable("ivy.resolver.default.check.modified");
+                return check != null ? Boolean.valueOf(check).booleanValue() : false;
+            } else {
+                return false;
+            }
+        } else {
+            return checkmodified.booleanValue();
+        }
+    }
+
+    public void setCheckmodified(boolean check) {
+        checkmodified = Boolean.valueOf(check);
+    }
+    
     /**
      * Returns a File object pointing to where the artifact can be found on the local file system.
      * This is usually in the cache, but it can be directly in the repository if it is local and if
@@ -349,80 +411,142 @@
     }
 
     public ResolvedModuleRevision findModuleInCache(
-            ModuleRevisionId mrid, boolean validate, String expectedResolver) {
-        if (!settings.getVersionMatcher().isDynamic(mrid)) {
-            if (!lockMetadataArtifact(mrid)) {
-                Message.error("impossible to acquire lock for " + mrid);
-                return null;
+            DependencyDescriptor dd, CacheMetadataOptions options, String expectedResolver) {
+        ModuleRevisionId mrid = dd.getDependencyRevisionId();
+        if (isCheckmodified(dd, options)) {
+            Message.verbose("don't use cache for " + mrid + ": checkModified=true");
+            return null;
+        }
+        if (isChanging(dd, options)) {
+            Message.verbose("don't use cache for " + mrid + ": changing=true");
+            return null;
+        }
+        return doFindModuleInCache(mrid, options, expectedResolver);
+    }
+
+    private ResolvedModuleRevision doFindModuleInCache(
+            ModuleRevisionId mrid, CacheMetadataOptions options, String expectedResolver) {
+        if (!lockMetadataArtifact(mrid)) {
+            Message.error("impossible to acquire lock for " + mrid);
+            return null;
+        }
+        try {
+            if (settings.getVersionMatcher().isDynamic(mrid)) {
+                String resolvedRevision = getResolvedRevision(mrid, options);
+                if (resolvedRevision != null) {
+                    Message.verbose("found resolved revision in cache: " 
+                        + mrid + " => " + resolvedRevision);
+                    mrid = ModuleRevisionId.newInstance(mrid, resolvedRevision);
+                } else {
+                    return null;
+                }
             }
-            try {
-                // first, check if it is in cache
-                File ivyFile = getIvyFileInCache(mrid);
-                if (ivyFile.exists()) {
-                    // found in cache !
-                    try {
-                        ModuleDescriptor depMD = XmlModuleDescriptorParser.getInstance()
-                            .parseDescriptor(settings, ivyFile.toURL(), validate);
-                        String resolverName = getSavedResolverName(depMD);
-                        String artResolverName = getSavedArtResolverName(depMD);
-                        DependencyResolver resolver = settings.getResolver(resolverName);
-                        if (resolver == null) {
-                            Message.debug("\tresolver not found: " + resolverName
-                                + " => trying to use the one configured for " + mrid);
-                            resolver = settings.getResolver(depMD.getResolvedModuleRevisionId());
-                            if (resolver != null) {
-                                Message.debug("\tconfigured resolver found for "
-                                    + depMD.getResolvedModuleRevisionId() + ": "
-                                    + resolver.getName() + ": saving this data");
-                                saveResolver(depMD, resolver.getName());
-                            }
-                        }
-                        DependencyResolver artResolver = settings.getResolver(artResolverName);
-                        if (artResolver == null) {
-                            artResolver = resolver;
-                        }
+
+            File ivyFile = getIvyFileInCache(mrid);
+            if (ivyFile.exists()) {
+                // found in cache !
+                try {
+                    ModuleDescriptor depMD = XmlModuleDescriptorParser.getInstance()
+                    .parseDescriptor(settings, ivyFile.toURL(), options.isValidate());
+                    String resolverName = getSavedResolverName(depMD);
+                    String artResolverName = getSavedArtResolverName(depMD);
+                    DependencyResolver resolver = settings.getResolver(resolverName);
+                    if (resolver == null) {
+                        Message.debug("\tresolver not found: " + resolverName
+                            + " => trying to use the one configured for " + mrid);
+                        resolver = settings.getResolver(depMD.getResolvedModuleRevisionId());
                         if (resolver != null) {
-                            Message.debug("\tfound ivy file in cache for " + mrid + " (resolved by "
-                                + resolver.getName() + "): " + ivyFile);
-                            if (expectedResolver == null 
-                                    || expectedResolver.equals(resolver.getName())) {
-                                MetadataArtifactDownloadReport madr 
-                                    = new MetadataArtifactDownloadReport(
-                                        depMD.getMetadataArtifact());
-                                madr.setDownloadStatus(DownloadStatus.NO);
-                                madr.setSearched(false);
-                                madr.setLocalFile(ivyFile);
-                                madr.setSize(ivyFile.length());
-                                madr.setArtifactOrigin(
-                                    getSavedArtifactOrigin(depMD.getMetadataArtifact()));
-                                return new ResolvedModuleRevision(
-                                    resolver, artResolver, depMD, madr);
-                            } else {
-                                Message.debug(
-                                    "found module in cache but with a different resolver: "
-                                    + "discarding: " + mrid 
-                                    + "; expected resolver=" + expectedResolver 
-                                    + "; resolver=" + resolver.getName());
-                            }
+                            Message.debug("\tconfigured resolver found for "
+                                + depMD.getResolvedModuleRevisionId() + ": "
+                                + resolver.getName() + ": saving this data");
+                            saveResolver(depMD, resolver.getName());
+                        }
+                    }
+                    DependencyResolver artResolver = settings.getResolver(artResolverName);
+                    if (artResolver == null) {
+                        artResolver = resolver;
+                    }
+                    if (resolver != null) {
+                        Message.debug("\tfound ivy file in cache for " + mrid + " (resolved by "
+                            + resolver.getName() + "): " + ivyFile);
+                        if (expectedResolver == null 
+                                || expectedResolver.equals(resolver.getName())) {
+                            MetadataArtifactDownloadReport madr 
+                            = new MetadataArtifactDownloadReport(
+                                depMD.getMetadataArtifact());
+                            madr.setDownloadStatus(DownloadStatus.NO);
+                            madr.setSearched(false);
+                            madr.setLocalFile(ivyFile);
+                            madr.setSize(ivyFile.length());
+                            madr.setArtifactOrigin(
+                                getSavedArtifactOrigin(depMD.getMetadataArtifact()));
+                            return new ResolvedModuleRevision(
+                                resolver, artResolver, depMD, madr);
                         } else {
-                            Message.debug("\tresolver not found: " + resolverName
-                                + " => cannot use cached ivy file for " + mrid);
+                            Message.debug(
+                                "found module in cache but with a different resolver: "
+                                + "discarding: " + mrid 
+                                + "; expected resolver=" + expectedResolver 
+                                + "; resolver=" + resolver.getName());
                         }
-                    } catch (Exception e) {
-                        // will try with resolver
-                        Message.debug("\tproblem while parsing cached ivy file for: " + mrid + ": "
-                            + e.getMessage());
+                    } else {
+                        Message.debug("\tresolver not found: " + resolverName
+                            + " => cannot use cached ivy file for " + mrid);
                     }
-                } else {
-                    Message.debug("\tno ivy file in cache for " + mrid + ": tried " + ivyFile);
+                } catch (Exception e) {
+                    // will try with resolver
+                    Message.debug("\tproblem while parsing cached ivy file for: " + mrid + ": "
+                        + e.getMessage());
                 }
-            } finally {
-                unlockMetadataArtifact(mrid);
+            } else {
+                Message.debug("\tno ivy file in cache for " + mrid + ": tried " + ivyFile);
             }
+        } finally {
+            unlockMetadataArtifact(mrid);
         }
         return null;
     }
 
+    private String getResolvedRevision(ModuleRevisionId mrid, CacheMetadataOptions options) {
+        String resolvedRevision = null;
+        if (options.isForce()) {
+            Message.verbose("refresh mode: no check for cached resolved revision for " + mrid);
+            return null;
+        }
+        PropertiesFile cachedResolvedRevision = getCachedDataFile(mrid);
+        String expiration = cachedResolvedRevision.getProperty("expiration.time");
+        if (expiration == null) {
+            Message.verbose("no cached resolved revision for " + mrid);
+            return null;
+        } 
+        if (System.currentTimeMillis() > Long.parseLong(expiration)) {
+            Message.verbose("cached resolved revision expired for " + mrid);
+            return null;
+        }
+        resolvedRevision = cachedResolvedRevision.getProperty("resolved.revision");
+        if (resolvedRevision == null) {
+            Message.verbose("no cached resolved revision value for " + mrid);
+            return null;
+        }
+        return resolvedRevision;
+    }
+
+    private void saveResolvedRevision(ModuleRevisionId mrid, String revision) {
+        PropertiesFile cachedResolvedRevision = getCachedDataFile(mrid);
+        cachedResolvedRevision.setProperty("expiration.time", getExpiration(mrid));
+        cachedResolvedRevision.setProperty("resolved.revision", revision);
+        cachedResolvedRevision.save();
+    }
+
+    private String getExpiration(ModuleRevisionId mrid) {
+        return String.valueOf(System.currentTimeMillis() + getTTL(mrid));
+    }
+
+    protected long getTTL(ModuleRevisionId mrid) {
+        // TODO: implement TTL rules
+        return defaultTTL;
+    }
+
     public String toString() {
         return name;
     }
@@ -561,6 +685,11 @@
                 mdFileInCache);
 
             saveResolvers(md, resolver.getName(), resolver.getName());
+            
+            if (getSettings().getVersionMatcher().isDynamic(md.getModuleRevisionId())) {
+                saveResolvedRevision(md.getModuleRevisionId(), rmr.getId().getRevision());
+            }
+                
             if (!md.isDefault()) {
                 rmr.getReport().setOriginalLocalFile(originalFileInCache);
             }
@@ -579,8 +708,9 @@
     }
 
     public ResolvedModuleRevision cacheModuleDescriptor(
-            DependencyResolver resolver, final ResolvedResource mdRef, Artifact moduleArtifact, 
-            ResourceDownloader downloader, CacheMetadataOptions options) throws ParseException {
+            DependencyResolver resolver, final ResolvedResource mdRef, DependencyDescriptor dd, 
+            Artifact moduleArtifact, ResourceDownloader downloader, CacheMetadataOptions options) 
+            throws ParseException {
         ModuleDescriptorParser parser = ModuleDescriptorParserRegistry
             .getInstance().getParser(mdRef.getResource());
         Date cachedPublicationDate = null;
@@ -593,14 +723,14 @@
         }
         try {
             // now let's see if we can find it in cache and if it is up to date
-            ResolvedModuleRevision rmr = findModuleInCache(mrid, options.isValidate(), null);
+            ResolvedModuleRevision rmr = doFindModuleInCache(mrid, options, null);
             if (rmr != null) {
                 if (rmr.getDescriptor().isDefault() && rmr.getResolver() != resolver) {
                     Message.verbose("\t" + getName() + ": found revision in cache: " + mrid
                         + " (resolved by " + rmr.getResolver().getName()
                         + "): but it's a default one, maybe we can find a better one");
                 } else {
-                    if (!options.isCheckmodified() && !options.isChanging()) {
+                    if (!isCheckmodified(dd, options) && !isChanging(dd, options)) {
                         Message.verbose("\t" + getName() + ": revision in cache: " + mrid);
                         rmr.getReport().setSearched(true);
                         return rmr;
@@ -615,7 +745,7 @@
                     } else {
                         Message.verbose("\t" + getName() + ": revision in cache is not up to date: "
                             + mrid);
-                        if (options.isChanging()) {
+                        if (isChanging(dd, options)) {
                             // ivy file has been updated, we should see if it has a new publication
                             // date to see if a new download is required (in case the dependency is
                             // a changing one)
@@ -684,7 +814,7 @@
                             removeSavedArtifactOrigin(transformedArtifact);
                         }
                     }
-                } else if (options.isChanging()) {
+                } else if (isChanging(dd, options)) {
                     Message.verbose(mrid
                         + " is changing, but has not changed: will trust cached artifacts if any");
                 }
@@ -763,9 +893,46 @@
         return DefaultArtifact.cloneWithAnotherName(moduleArtifact, 
             moduleArtifact.getName() + ".original");
     }
+    
+
+    private boolean isChanging(DependencyDescriptor dd, CacheMetadataOptions options) {
+        return dd.isChanging() 
+            || getChangingMatcher(options).matches(dd.getDependencyRevisionId().getRevision());
+    }
+
+    private Matcher getChangingMatcher(CacheMetadataOptions options) {
+        String changingPattern = options.getChangingPattern() != null 
+                ? options.getChangingPattern() : this.changingPattern;
+        if (changingPattern == null) {
+            return NoMatcher.INSTANCE;
+        }
+        String changingMatcherName = options.getChangingMatcherName() != null 
+            ? options.getChangingMatcherName() : this.changingMatcherName;
+        PatternMatcher matcher = settings.getMatcher(changingMatcherName);
+        if (matcher == null) {
+            throw new IllegalStateException("unknown matcher '" + changingMatcherName
+                    + "'. It is set as changing matcher in " + this);
+        }
+        return matcher.getMatcher(changingPattern);
+    }
 
+    private boolean isCheckmodified(DependencyDescriptor dd, CacheMetadataOptions options) {
+        if (options.isCheckmodified() != null) {
+            return options.isCheckmodified().booleanValue();
+        }
+        return isCheckmodified();
+    }
+    
     public void clean() {
         FileUtil.forceDelete(getBasedir());
     }
-    
+
+    public void dumpSettings() {
+        Message.verbose("\t" + getName());
+        Message.debug("\t\tivyPattern: " + getIvyPattern());
+        Message.debug("\t\tartifactPattern: " + getArtifactPattern());
+        Message.debug("\t\tlockingStrategy: " + getLockStrategy().getName());
+        Message.debug("\t\tchangingPattern: " + getChangingPattern());
+        Message.debug("\t\tchangingMatcher: " + getChangingMatcherName());
+    }
 }

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/RepositoryCacheManager.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/RepositoryCacheManager.java?rev=610936&r1=610935&r2=610936&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/RepositoryCacheManager.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/RepositoryCacheManager.java Thu Jan 10 13:28:31 2008
@@ -20,8 +20,8 @@
 import java.text.ParseException;
 
 import org.apache.ivy.core.module.descriptor.Artifact;
+import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
 import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
-import org.apache.ivy.core.module.id.ModuleRevisionId;
 import org.apache.ivy.core.report.ArtifactDownloadReport;
 import org.apache.ivy.core.resolve.ResolvedModuleRevision;
 import org.apache.ivy.plugins.repository.ArtifactResourceResolver;
@@ -40,7 +40,7 @@
     /**
      * Saves the information of which resolvers were used to resolve a module (both for metadata and
      * artifact), so that this info can be loaded later (even after a jvm restart) for the use of
-     * {@link #findModuleInCache(ModuleRevisionId, boolean, String)}.
+     * {@link #findModuleInCache(DependencyDescriptor, CacheMetadataOptions, String)}.
      * 
      * @param md
      *            the module descriptor resolved
@@ -65,10 +65,10 @@
     /**
      * Search a module descriptor in cache for a mrid
      * 
-     * @param mrid
-     *            the id of the module to search
-     * @param validate
-     *            true to validate ivy file found in cache before returning
+     * @param dd
+     *            the dependency descriptor identifying the module to search
+     * @param options
+     *            options on how caching should be handled
      * @param expectedResolver
      *            the resolver with which the md in cache must have been resolved to be returned,
      *            null if this doesn't matter
@@ -76,7 +76,7 @@
      *         has been found in cache
      */
     public abstract ResolvedModuleRevision findModuleInCache(
-            ModuleRevisionId mrid, boolean validate, String expectedResolver);
+            DependencyDescriptor dd, CacheMetadataOptions options, String expectedResolver);
     
     /**
      * Downloads an artifact to this cache.
@@ -109,6 +109,8 @@
      *            the dependency resolver from which the cache request comes from
      * @param orginalMetadataRef
      *            a resolved resource pointing to the remote original module descriptor
+     * @param dd
+     *            the dependency descriptor for which the module descriptor should be cached
      * @param requestedMetadataArtifact
      *            the module descriptor artifact as requested originally
      * @param downloader
@@ -122,8 +124,9 @@
      *             if an exception occured while parsing the module descriptor
      */
     public ResolvedModuleRevision cacheModuleDescriptor(DependencyResolver resolver,
-            ResolvedResource orginalMetadataRef, Artifact requestedMetadataArtifact,
-            ResourceDownloader downloader, CacheMetadataOptions options) throws ParseException;
+            ResolvedResource orginalMetadataRef, DependencyDescriptor dd, 
+            Artifact requestedMetadataArtifact,  ResourceDownloader downloader, 
+            CacheMetadataOptions options) throws ParseException;
 
     /**
      * Stores a standardized version of an original module descriptor in the cache for later use.

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolveEngine.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolveEngine.java?rev=610936&r1=610935&r2=610936&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolveEngine.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolveEngine.java Thu Jan 10 13:28:31 2008
@@ -218,6 +218,7 @@
                     + (options.isTransitive() ? "" : " [not transitive]"));
             Message.info("\tconfs: " + Arrays.asList(confs));
             Message.verbose("\tvalidate = " + options.isValidate());
+            Message.verbose("\trefresh = " + options.isRefresh());
             ResolveReport report = new ResolveReport(md, options.getResolveId());
 
             // resolve dependencies

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolveOptions.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolveOptions.java?rev=610936&r1=610935&r2=610936&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolveOptions.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/resolve/ResolveOptions.java Thu Jan 10 13:28:31 2008
@@ -96,6 +96,8 @@
      */
     private String resolveId;
 
+    private boolean refresh;
+
     public ResolveOptions() {
     }
 
@@ -104,6 +106,7 @@
         revision = options.revision;
         date = options.date;
         validate = options.validate;
+        refresh = options.refresh;
         useCacheOnly = options.useCacheOnly;
         transitive = options.transitive;
         download = options.download;
@@ -246,6 +249,15 @@
     public ResolveOptions setResolveId(String resolveId) {
         this.resolveId = resolveId;
         return this;
+    }
+
+    public ResolveOptions setRefresh(boolean refresh) {
+        this.refresh = refresh;
+        return this;
+    }
+    
+    public boolean isRefresh() {
+        return refresh;
     }
 
 

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java?rev=610936&r1=610935&r2=610936&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java Thu Jan 10 13:28:31 2008
@@ -17,11 +17,20 @@
  */
 package org.apache.ivy.plugins.resolver;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.Map;
 
 import org.apache.ivy.core.IvyContext;
+import org.apache.ivy.core.cache.ArtifactOrigin;
+import org.apache.ivy.core.cache.CacheDownloadOptions;
+import org.apache.ivy.core.cache.CacheMetadataOptions;
+import org.apache.ivy.core.cache.DownloadListener;
 import org.apache.ivy.core.cache.RepositoryCacheManager;
+import org.apache.ivy.core.event.EventManager;
+import org.apache.ivy.core.event.download.EndArtifactDownloadEvent;
+import org.apache.ivy.core.event.download.NeedArtifactEvent;
+import org.apache.ivy.core.event.download.StartArtifactDownloadEvent;
 import org.apache.ivy.core.module.descriptor.Artifact;
 import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
 import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
@@ -37,12 +46,10 @@
 import org.apache.ivy.core.search.OrganisationEntry;
 import org.apache.ivy.core.search.RevisionEntry;
 import org.apache.ivy.plugins.latest.LatestStrategy;
-import org.apache.ivy.plugins.matcher.Matcher;
-import org.apache.ivy.plugins.matcher.NoMatcher;
-import org.apache.ivy.plugins.matcher.PatternMatcher;
 import org.apache.ivy.plugins.namespace.NameSpaceHelper;
 import org.apache.ivy.plugins.namespace.Namespace;
 import org.apache.ivy.plugins.resolver.util.HasLatestStrategy;
+import org.apache.ivy.plugins.resolver.util.ResolvedResource;
 import org.apache.ivy.util.Message;
 
 /**
@@ -58,11 +65,9 @@
 
     private String name;
 
-    private String changingPattern;
-
-    private String changingMatcherName = PatternMatcher.EXACT_OR_REGEXP;
-
     private ResolverSettings settings;
+    
+    private EventManager eventManager = null; // may remain null
 
     /**
      * The latest strategy to use to find latest among several artifacts
@@ -82,6 +87,13 @@
     
     private RepositoryCacheManager repositoryCacheManager;
 
+    // used to store default values for nested cache
+    private String changingMatcherName;
+
+    private String changingPattern;
+
+    private Boolean checkmodified;
+
     public ResolverSettings getSettings() {
         return settings;
     }
@@ -159,8 +171,6 @@
 
     public void dumpSettings() {
         Message.verbose("\t" + getName() + " [" + getTypeName() + "]");
-        Message.debug("\t\tchangingPattern: " + getChangingPattern());
-        Message.debug("\t\tchangingMatcher: " + getChangingMatcherName());
         Message.debug("\t\tcache: " + cacheManagerName);
     }
 
@@ -274,42 +284,35 @@
         return data.getNode(toSystem(resolvedMrid));
     }
 
-    protected ResolvedModuleRevision findModuleInCache(ResolveData data, ModuleRevisionId mrid) {
-        return findModuleInCache(data, mrid, false);
+    protected ResolvedModuleRevision findModuleInCache(
+            DependencyDescriptor dd, CacheMetadataOptions options) {
+        return findModuleInCache(dd, options, false);
     }
 
     protected ResolvedModuleRevision findModuleInCache(
-            ResolveData data, ModuleRevisionId mrid, boolean anyResolver) {
+            DependencyDescriptor dd, CacheMetadataOptions options, boolean anyResolver) {
         return getRepositoryCacheManager().findModuleInCache(
-            mrid, doValidate(data), anyResolver ? null : getName());
-    }
-
-    public String getChangingMatcherName() {
-        return changingMatcherName;
+            dd, options, anyResolver ? null : getName());
     }
 
     public void setChangingMatcher(String changingMatcherName) {
         this.changingMatcherName = changingMatcherName;
     }
-
-    public String getChangingPattern() {
-        return changingPattern;
+    
+    protected String getChangingMatcherName() {
+        return changingMatcherName;
     }
 
     public void setChangingPattern(String changingPattern) {
         this.changingPattern = changingPattern;
     }
+    
+    protected String getChangingPattern() {
+        return changingPattern;
+    }
 
-    public Matcher getChangingMatcher() {
-        if (changingPattern == null) {
-            return NoMatcher.INSTANCE;
-        }
-        PatternMatcher matcher = settings.getMatcher(changingMatcherName);
-        if (matcher == null) {
-            throw new IllegalStateException("unknown matcher '" + changingMatcherName
-                    + "'. It is set as changing matcher in " + this);
-        }
-        return matcher.getMatcher(changingPattern);
+    public void setCheckmodified(boolean check) {
+        checkmodified = Boolean.valueOf(check);
     }
     
     public RepositoryCacheManager getRepositoryCacheManager() {
@@ -331,6 +334,29 @@
         cacheManagerName = cacheName;
     }
     
+    public void setEventManager(EventManager eventManager) {
+        this.eventManager = eventManager;
+    }
+    
+    public EventManager getEventManager() {
+        return eventManager;
+    }
+
+    protected CacheMetadataOptions getCacheOptions(ResolveData data) {
+        return (CacheMetadataOptions) new CacheMetadataOptions()
+            .setChangingMatcherName(getChangingMatcherName())
+            .setChangingPattern(getChangingPattern())
+            .setCheckmodified(checkmodified)
+            .setValidate(doValidate(data))
+            .setNamespace(getNamespace())
+            .setForce(data.getOptions().isRefresh())
+            .setListener(downloadListener);
+    }
+
+    protected CacheDownloadOptions getCacheDownloadOptions() {
+        return new CacheDownloadOptions().setListener(downloadListener);
+    }
+    
     public void abortPublishTransaction() throws IOException {
         /* Default implementation is a no-op */
     }
@@ -344,5 +370,35 @@
         /* Default implementation is a no-op */
     }
 
+    private final DownloadListener downloadListener = new DownloadListener() {
+        public void needArtifact(RepositoryCacheManager cache, Artifact artifact) {
+            if (eventManager != null) {
+                eventManager.fireIvyEvent(new NeedArtifactEvent(AbstractResolver.this, artifact));
+            }
+        }
+        public void startArtifactDownload(
+                RepositoryCacheManager cache, ResolvedResource rres, 
+                Artifact artifact, ArtifactOrigin origin) {
+            if (artifact.isMetadata()) {
+                Message.verbose("downloading " + rres.getResource() + " ...");
+            } else {
+                Message.info("downloading " + rres.getResource() + " ...");
+            }
+            if (eventManager != null) {
+                eventManager.fireIvyEvent(
+                    new StartArtifactDownloadEvent(
+                        AbstractResolver.this, artifact, origin));
+            }            
+        }
+        public void endArtifactDownload(
+                RepositoryCacheManager cache, Artifact artifact, 
+                ArtifactDownloadReport adr, File archiveFile) {
+            if (eventManager != null) {
+                eventManager.fireIvyEvent(
+                    new EndArtifactDownloadEvent(
+                        AbstractResolver.this, artifact, adr, archiveFile));
+            }
+        }
+    };
 
 }

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/BasicResolver.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/BasicResolver.java?rev=610936&r1=610935&r2=610936&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/BasicResolver.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/BasicResolver.java Thu Jan 10 13:28:31 2008
@@ -97,15 +97,11 @@
 
     private Map artattempts = new HashMap();
 
-    private Boolean checkmodified = null;
-
     private boolean checkconsistency = true;
 
     private boolean allownomd = true;
 
     private String checksums = null;
-    
-    private EventManager eventManager = null; // may remain null
 
     private URLRepository extartifactrep = new URLRepository(); // used only to download
 
@@ -130,36 +126,6 @@
     public void setEnvDependent(boolean envDependent) {
         this.envDependent = envDependent;
     }
-    
-    public void setEventManager(EventManager eventManager) {
-        this.eventManager = eventManager;
-    }
-    
-    public EventManager getEventManager() {
-        return eventManager;
-    }
-
-    /**
-     * True if this resolver should check lastmodified date to know if ivy files are up to date.
-     * 
-     * @return
-     */
-    public boolean isCheckmodified() {
-        if (checkmodified == null) {
-            if (getSettings() != null) {
-                String check = getSettings().getVariable("ivy.resolver.default.check.modified");
-                return check != null ? Boolean.valueOf(check).booleanValue() : false;
-            } else {
-                return false;
-            }
-        } else {
-            return checkmodified.booleanValue();
-        }
-    }
-
-    public void setCheckmodified(boolean check) {
-        checkmodified = Boolean.valueOf(check);
-    }
 
     public ResolvedModuleRevision getDependency(DependencyDescriptor dde, ResolveData data)
             throws ParseException {
@@ -190,30 +156,23 @@
                 return null;
             }
 
-            boolean isChangingRevision = getChangingMatcher().matches(systemMrid.getRevision());
-            boolean isChangingDependency = isChangingRevision || systemDd.isChanging();
-
-            // if we do not have to check modified and if the revision is exact and not changing,
-            // we first search for it in cache
-            ResolvedModuleRevision cachedRmr = null;
-            boolean checkedCache = false;
-            if (!isDynamic && !isCheckmodified() && !isChangingDependency) {
-                cachedRmr = findModuleInCache(data, systemMrid);
-                checkedCache = true;
-                if (cachedRmr != null) {
-                    if (cachedRmr.getDescriptor().isDefault() && cachedRmr.getResolver() != this) {
-                        Message.verbose("\t" + getName() + ": found revision in cache: " 
-                            + systemMrid
-                            + " (resolved by " + cachedRmr.getResolver().getName()
-                            + "): but it's a default one, maybe we can find a better one");
-                    } else {
-                        Message.verbose("\t" + getName() + ": revision in cache: " + systemMrid);
-                        return cachedRmr;
-                    }
+            // we first search for the dependency in cache
+            ResolvedModuleRevision rmr = null;
+            rmr = findModuleInCache(systemDd, getCacheOptions(data));
+            if (rmr != null) {
+                if (rmr.getDescriptor().isDefault() && rmr.getResolver() != this) {
+                    Message.verbose("\t" + getName() + ": found revision in cache: " 
+                        + systemMrid
+                        + " (resolved by " + rmr.getResolver().getName()
+                        + "): but it's a default one, maybe we can find a better one");
+                } else {
+                    Message.verbose("\t" + getName() + ": revision in cache: " + systemMrid);
+                    return rmr;
                 }
             }
+            
             checkInterrupted();
-            ResolvedModuleRevision rmr = null;
+            
             ResolvedResource ivyRef = findIvyFileRef(nsDd, data);
             checkInterrupted();
 
@@ -234,13 +193,6 @@
                 if (artifactRef == null) {
                     Message.verbose("\t" + getName() + ": no ivy file nor artifact found for "
                         + systemMrid);
-                    if (!checkedCache) {
-                        cachedRmr = findModuleInCache(data, systemMrid);
-                    }
-                    if (cachedRmr != null) {
-                        Message.verbose("\t" + getName() + ": revision in cache: " + systemMrid);
-                        return cachedRmr;
-                    }
                     return null;
                 } else {
                     long lastModified = artifactRef.getLastModified();
@@ -463,16 +415,9 @@
         }
 
         Artifact moduleArtifact = parser.getMetadataArtifact(resolvedMrid, mdRef.getResource());
-        boolean isChangingRevision = getChangingMatcher().matches(mrid.getRevision());
-        boolean isChangingDependency = isChangingRevision || dd.isChanging();
         return getRepositoryCacheManager().cacheModuleDescriptor(
-            this, mdRef, moduleArtifact, downloader, 
-            (CacheMetadataOptions) new CacheMetadataOptions()
-                .setChanging(isChangingDependency)
-                .setCheckmodified(isCheckmodified())
-                .setValidate(doValidate(data))
-                .setNamespace(getNamespace())
-                .setListener(downloadListener));
+            this, mdRef, dd, moduleArtifact, downloader, 
+            getCacheOptions(data));
     }
 
     protected ResourceMDParser getRMDParser(final DependencyDescriptor dd, final ResolveData data) {
@@ -629,7 +574,7 @@
         for (int i = 0; i < artifacts.length; i++) {
             ArtifactDownloadReport adr = cacheManager.download(
                 artifacts[i], artifactResourceResolver, downloader, 
-                new CacheDownloadOptions().setListener(downloadListener)
+                getCacheDownloadOptions()
                     .setUseOrigin(options.isUseOrigin()));
             if (DownloadStatus.FAILED == adr.getDownloadStatus()) {
                 if (!ArtifactDownloadReport.MISSING_ARTIFACT.equals(adr.getDownloadDetails())) {
@@ -873,34 +818,4 @@
         }
     };
 
-    private final DownloadListener downloadListener = new DownloadListener() {
-        public void needArtifact(RepositoryCacheManager cache, Artifact artifact) {
-            if (eventManager != null) {
-                eventManager.fireIvyEvent(new NeedArtifactEvent(BasicResolver.this, artifact));
-            }
-        }
-        public void startArtifactDownload(
-                RepositoryCacheManager cache, ResolvedResource rres, 
-                Artifact artifact, ArtifactOrigin origin) {
-            if (artifact.isMetadata()) {
-                Message.verbose("downloading " + rres.getResource() + " ...");
-            } else {
-                Message.info("downloading " + rres.getResource() + " ...");
-            }
-            if (eventManager != null) {
-                eventManager.fireIvyEvent(
-                    new StartArtifactDownloadEvent(
-                        BasicResolver.this, artifact, origin));
-            }            
-        }
-        public void endArtifactDownload(
-                RepositoryCacheManager cache, Artifact artifact, 
-                ArtifactDownloadReport adr, File archiveFile) {
-            if (eventManager != null) {
-                eventManager.fireIvyEvent(
-                    new EndArtifactDownloadEvent(
-                        BasicResolver.this, artifact, adr, archiveFile));
-            }
-        }
-    };
 }

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/CacheResolver.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/CacheResolver.java?rev=610936&r1=610935&r2=610936&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/CacheResolver.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/CacheResolver.java Thu Jan 10 13:28:31 2008
@@ -26,6 +26,7 @@
 import org.apache.ivy.core.cache.DefaultRepositoryCacheManager;
 import org.apache.ivy.core.cache.RepositoryCacheManager;
 import org.apache.ivy.core.module.descriptor.Artifact;
+import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
 import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
 import org.apache.ivy.core.module.id.ModuleRevisionId;
 import org.apache.ivy.core.report.ArtifactDownloadReport;
@@ -58,18 +59,14 @@
         ModuleRevisionId mrid = dd.getDependencyRevisionId();
         // check revision
 
-        // if we do not have to check modified and if the revision is exact and not changing,
-        // we first search for it in cache
-        if (!getSettings().getVersionMatcher().isDynamic(mrid)) {
-            ResolvedModuleRevision rmr = getRepositoryCacheManager()
-                .findModuleInCache(mrid, doValidate(data), null);
-            if (rmr != null) {
-                Message.verbose("\t" + getName() + ": revision in cache: " + mrid);
-                return rmr;
-            } else {
-                Message.verbose("\t" + getName() + ": no ivy file in cache found for " + mrid);
-                return null;
-            }
+        ResolvedModuleRevision rmr = getRepositoryCacheManager()
+            .findModuleInCache(dd, getCacheOptions(data), null);
+        if (rmr != null) {
+            Message.verbose("\t" + getName() + ": revision in cache: " + mrid);
+            return rmr;
+        } else if (!getSettings().getVersionMatcher().isDynamic(mrid)) {
+            Message.verbose("\t" + getName() + ": no ivy file in cache found for " + mrid);
+            return null;
         } else {
             ensureConfigured();
             ResolvedResource ivyRef = findIvyFileRef(dd, data);
@@ -86,8 +83,9 @@
                             + resolvedMrid);
                     return node.getModuleRevision();
                 }
-                ResolvedModuleRevision rmr = getRepositoryCacheManager()
-                    .findModuleInCache(resolvedMrid, doValidate(data), null);
+                rmr = getRepositoryCacheManager().findModuleInCache(
+                        new DefaultDependencyDescriptor(dd, ivyRef.getRevision()), 
+                        getCacheOptions(data), null);
                 if (rmr != null) {
                     Message.verbose("\t" + getName() + ": revision in cache: " + resolvedMrid);
                     return rmr;

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java?rev=610936&r1=610935&r2=610936&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ChainResolver.java Thu Jan 10 13:28:31 2008
@@ -107,21 +107,15 @@
 
         ModuleRevisionId mrid = dd.getDependencyRevisionId();
 
-        boolean isDynamic = getSettings().getVersionMatcher().isDynamic(mrid);
-
-        boolean isChangingRevision = getChangingMatcher().matches(mrid.getRevision());
-        boolean isChangingDependency = isChangingRevision || dd.isChanging();
 
-        if (!isDynamic && !isCheckmodified() && !isChangingDependency) {
-            Message.verbose(getName() + ": not dynamic, not check modified and not changing."
-                    + " Checking cache for: " + mrid);
-            mr = findModuleInCache(data, mrid, true);
-            if (mr != null) {
-                Message.verbose("chain " + getName() + ": module revision found in cache: " + mrid);
-                return resolvedRevision(mr);
-            }
+        Message.verbose(getName() + ": Checking cache for: " + dd);
+        mr = findModuleInCache(dd, getCacheOptions(data), true);
+        if (mr != null) {
+            Message.verbose(getName() + ": module revision found in cache: " + mr.getId());
+            return resolvedRevision(mr);
         }
 
+        boolean isDynamic = getSettings().getVersionMatcher().isDynamic(mrid);
         for (Iterator iter = chain.iterator(); iter.hasNext();) {
             DependencyResolver resolver = (DependencyResolver) iter.next();
             LatestStrategy oldLatest = setLatestIfRequired(resolver, getLatestStrategy());

Modified: ant/ivy/core/trunk/test/java/org/apache/ivy/core/resolve/ResolveTest.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/core/resolve/ResolveTest.java?rev=610936&r1=610935&r2=610936&view=diff
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/core/resolve/ResolveTest.java (original)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/core/resolve/ResolveTest.java Thu Jan 10 13:28:31 2008
@@ -55,8 +55,6 @@
 import org.apache.ivy.plugins.resolver.FileSystemResolver;
 import org.apache.ivy.util.CacheCleaner;
 import org.apache.ivy.util.FileUtil;
-import org.apache.tools.ant.Project;
-import org.apache.tools.ant.taskdefs.Delete;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
@@ -372,22 +370,10 @@
     public void testFromCache2() throws Exception {
         // mod1.1 depends on mod1.2
 
-        // configuration
-        Ivy ivy = Ivy.newInstance();
-        DualResolver resolver = new DualResolver();
-        resolver.setName("dual");
-        FileSystemResolver r = new FileSystemResolver();
-        r.setName("1");
-        r.addArtifactPattern("build/testCache2/[artifact]-[revision].[ext]");
-        resolver.add(r);
-        r = new FileSystemResolver();
-        r.setName("2");
-        r.addArtifactPattern("build/testCache2/[artifact]-[revision].[ext]");
-        resolver.add(r);
-        ivy.getSettings().addResolver(resolver);
-        ivy.getSettings().setDefaultResolver("dual");
+        Ivy ivy = ivyTestCache();
 
         // set up repository
+        FileUtil.forceDelete(new File("build/testCache2"));
         File art = new File("build/testCache2/mod1.2-2.0.jar");
         FileUtil.copy(new File("test/repositories/1/org1/mod1.2/jars/mod1.2-2.0.jar"), art, null);
 
@@ -398,10 +384,7 @@
         assertFalse(report.hasError());
 
         // now we clean the repository to simulate repo not available (network pb for instance)
-        Delete del = new Delete();
-        del.setProject(new Project());
-        del.setDir(new File("build/testCache2"));
-        del.execute();
+        FileUtil.forceDelete(new File("build/testCache2"));
 
         // now do a new resolve: it should use cached data
         report = ivy.resolve(new File("test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml").toURL(),
@@ -419,6 +402,111 @@
         assertTrue(getIvyFileInCache(
             ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists());
         assertTrue(getArchiveFileInCache("org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists());
+    }
+
+    public void testDynamicFromCache1() throws Exception {
+        // mod1.4;1.0.2 depends on mod1.2;[1.0,2.0[
+
+        Ivy ivy = ivyTestCache();
+
+        // set up repository
+        FileUtil.forceDelete(new File("build/testCache2"));
+        FileUtil.copy(
+            new File("test/repositories/1/org1/mod1.2/jars/mod1.2-2.0.jar"), 
+            new File("build/testCache2/mod1.2-1.5.jar"), null);
+
+        // we first do a simple resolve so that module is in cache
+        ResolveReport report = ivy.resolve(new File(
+                "test/repositories/1/org1/mod1.4/ivys/ivy-1.0.2.xml").toURL(),
+            getResolveOptions(new String[] {"*"}));
+        assertFalse(report.hasError());
+
+        assertEquals(
+            new HashSet(Arrays.asList(new ModuleRevisionId[] {
+                    ModuleRevisionId.newInstance("org1", "mod1.2", "1.5")})), 
+            report.getConfigurationReport("default").getModuleRevisionIds());
+
+        // now we clean the repository to simulate repo not available (network pb for instance)
+        FileUtil.forceDelete(new File("build/testCache2"));
+
+        // now do a new resolve: it should use cached data
+        report = ivy.resolve(new File("test/repositories/1/org1/mod1.4/ivys/ivy-1.0.2.xml").toURL(),
+            getResolveOptions(new String[] {"*"}));
+        assertFalse(report.hasError());
+        
+        assertEquals(
+            new HashSet(Arrays.asList(new ModuleRevisionId[] {
+                    ModuleRevisionId.newInstance("org1", "mod1.2", "1.5")})), 
+            report.getConfigurationReport("default").getModuleRevisionIds());
+    }
+
+
+    public void testRefreshDynamicFromCache() throws Exception {
+        // mod1.4;1.0.2 depends on mod1.2;[1.0,2.0[
+        Ivy ivy = ivyTestCache();
+
+        // set up repository
+        FileUtil.forceDelete(new File("build/testCache2"));
+        FileUtil.copy(
+            new File("test/repositories/1/org1/mod1.2/jars/mod1.2-2.0.jar"), 
+            new File("build/testCache2/mod1.2-1.5.jar"), null);
+
+        // we first do a simple resolve so that module is in cache
+        ResolveReport report = ivy.resolve(new File(
+                "test/repositories/1/org1/mod1.4/ivys/ivy-1.0.2.xml").toURL(),
+            getResolveOptions(new String[] {"*"}));
+        assertFalse(report.hasError());
+
+        // now we update the repository
+        FileUtil.copy(
+            new File("test/repositories/1/org1/mod1.2/jars/mod1.2-2.0.jar"), 
+            new File("build/testCache2/mod1.2-1.6.jar"), null);
+
+        // now do a new resolve: it should use cached data
+        report = ivy.resolve(new File("test/repositories/1/org1/mod1.4/ivys/ivy-1.0.2.xml").toURL(),
+            getResolveOptions(new String[] {"*"}));
+        assertFalse(report.hasError());
+        
+        assertEquals(
+            new HashSet(Arrays.asList(new ModuleRevisionId[] {
+                    ModuleRevisionId.newInstance("org1", "mod1.2", "1.5")})), 
+            report.getConfigurationReport("default").getModuleRevisionIds());
+
+        // resolve again with refresh: it should find the new version
+        report = ivy.resolve(new File("test/repositories/1/org1/mod1.4/ivys/ivy-1.0.2.xml").toURL(),
+            getResolveOptions(new String[] {"*"}).setRefresh(true));
+        assertFalse(report.hasError());
+        
+        assertEquals(
+            new HashSet(Arrays.asList(new ModuleRevisionId[] {
+                    ModuleRevisionId.newInstance("org1", "mod1.2", "1.6")})), 
+            report.getConfigurationReport("default").getModuleRevisionIds());
+        
+        FileUtil.forceDelete(new File("build/testCache2"));
+    }
+
+    /**
+     * Configures an Ivy instance using a resolver locating modules on file system, in a
+     * build/testCache2 location which is created for the test and removed after, and can thus
+     * easily simulate a repository availability problem
+     * 
+     * @return the configured ivy instance
+     */
+    private Ivy ivyTestCache() {
+        Ivy ivy = Ivy.newInstance();
+        DualResolver resolver = new DualResolver();
+        resolver.setName("dual");
+        FileSystemResolver r = new FileSystemResolver();
+        r.setName("1");
+        r.addArtifactPattern("build/testCache2/[artifact]-[revision].[ext]");
+        resolver.add(r);
+        r = new FileSystemResolver();
+        r.setName("2");
+        r.addArtifactPattern("build/testCache2/[artifact]-[revision].[ext]");
+        resolver.add(r);
+        ivy.getSettings().addResolver(resolver);
+        ivy.getSettings().setDefaultResolver("dual");
+        return ivy;
     }
 
     public void testFromCacheOnly() throws Exception {