ant-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gscok...@apache.org
Subject svn commit: r685906 - in /ant/ivy/core/trunk: ./ doc/settings/caches/ src/java/org/apache/ivy/core/ src/java/org/apache/ivy/core/cache/ src/java/org/apache/ivy/core/settings/ test/java/org/apache/ivy/core/cache/
Date Thu, 14 Aug 2008 14:11:21 GMT
Author: gscokart
Date: Thu Aug 14 07:11:20 2008
New Revision: 685906

URL: http://svn.apache.org/viewvc?rev=685906&view=rev
Log:
IMPROVEMENT: Add a memory cache for the module descriptor that are parsed from the cache (IVY-883)

Added:
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCache.java
  (with props)
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorProvider.java  
(with props)
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ParserSettingsMonitor.java   (with
props)
    ant/ivy/core/trunk/test/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCacheTest.java
  (with props)
Modified:
    ant/ivy/core/trunk/CHANGES.txt
    ant/ivy/core/trunk/doc/settings/caches/cache.html
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/IvyPatternHelper.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/IvySettings.java

Modified: ant/ivy/core/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/CHANGES.txt?rev=685906&r1=685905&r2=685906&view=diff
==============================================================================
--- ant/ivy/core/trunk/CHANGES.txt (original)
+++ ant/ivy/core/trunk/CHANGES.txt Thu Aug 14 07:11:20 2008
@@ -105,6 +105,7 @@
 - IMPROVEMENT: Smarter determination if an expression is exact or not for RegexpPatternMatcher
and GlobPatternMatcher
 - IMPROVEMENT: Check branch consistency during resolve (IVY-858)
 - IMPROVEMENT: Give the possibility to not compute ivy.deps.changed (IVY-876)
+- IMPROVEMENT: Add a memory cache for the module descriptor that are parsed from the cache
(IVY-883)
 - IMPROVEMENT: Improve performance (IVY-872)
 
 - FIX: Incorrect parsing artifactPattern attribute in a sftp resolver (IVY-661) (thanks to
Alexey Kiselev)

Modified: ant/ivy/core/trunk/doc/settings/caches/cache.html
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/doc/settings/caches/cache.html?rev=685906&r1=685905&r2=685906&view=diff
==============================================================================
--- ant/ivy/core/trunk/doc/settings/caches/cache.html (original)
+++ ant/ivy/core/trunk/doc/settings/caches/cache.html Thu Aug 14 07:11:20 2008
@@ -26,10 +26,14 @@
 	<textarea id="xooki-source">
 <b>Tag:</b> cache
 
+<span class="since">Since 2.0</span>.
+
 <span class="tagdoc" id="ivysettings.caches.cache">Defines a repository cache instance
based on the default repository cache implementation.</span>
 
 The default repository cache implementation caches files on the local filesystem in subdirectories
of a configured base directory.
 
+By default also, the parsed module descriptor read from the cache are kept in a memory cache
in case they are reused.  This may enhance the performance of multi-module build, provided
that all modules are build using the same ivy instance.  The size of this memory cache is
configurable in term of number of module descriptors.  A size of 0 means no memory caching.
+
 <h1>Attributes</h1>
 <table class="ivy-attributes">
 <thead>
@@ -51,6 +55,7 @@
         <td>No, defaults to default lock strategy as configured in [[settings/caches]]</td></tr>
     <tr><td>defaultTTL</td><td>the default [[settings/caches/ttl
TTL]] to use when no specific one is defined</td>
         <td>No, defaults to ${ivy.cache.ttl.default}</td></tr>
+    <tr><td>memorySize</td><td>the number of parsed module descriptors
to keep in a memory cache.</td><td>No, default to 150</td></tr>
 </tbody>
 </table>
 

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/IvyPatternHelper.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/IvyPatternHelper.java?rev=685906&r1=685905&r2=685906&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/IvyPatternHelper.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/IvyPatternHelper.java Thu Aug 14 07:11:20
2008
@@ -171,8 +171,13 @@
 
         Matcher m = VAR_PATTERN.matcher(pattern);
 
-        StringBuffer sb = new StringBuffer();
+        boolean useVariables = false;
+        StringBuffer sb = null;
         while (m.find()) {
+            if (!useVariables) {
+                useVariables = true;
+                sb = new StringBuffer();
+            }
             String var = m.group(1);
             String val = (String) variables.getVariable(var);
             if (val != null) {
@@ -189,13 +194,15 @@
             } else {
                 val = m.group();
             }
-            m
-                    .appendReplacement(sb, val.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\$",
-                        "\\\\\\$"));
+            m.appendReplacement(sb, val.replaceAll("\\\\", "\\\\\\\\")
+                .replaceAll("\\$","\\\\\\$"));
+        }
+        if (useVariables) {
+            m.appendTail(sb);
+            return sb.toString();
+        } else {
+            return pattern;
         }
-        m.appendTail(sb);
-
-        return sb.toString();
     }
 
     public static String substituteTokens(String pattern, Map tokens) {

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=685906&r1=685905&r2=685906&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 Aug 14 07:11:20 2008
@@ -20,7 +20,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.net.MalformedURLException;
-import java.net.URL;
 import java.text.ParseException;
 import java.util.Date;
 import java.util.Map;
@@ -48,6 +47,7 @@
 import org.apache.ivy.plugins.namespace.NameSpaceHelper;
 import org.apache.ivy.plugins.parser.ModuleDescriptorParser;
 import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry;
+import org.apache.ivy.plugins.parser.ParserSettings;
 import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorParser;
 import org.apache.ivy.plugins.repository.ArtifactResourceResolver;
 import org.apache.ivy.plugins.repository.ResourceDownloader;
@@ -68,6 +68,8 @@
     private static final String DEFAULT_IVY_PATTERN = 
         "[organisation]/[module](/[branch])/ivy-[revision].xml";
     
+    private static final int DEFAULT_MEMORY_CACHE_SIZE = 150;
+    
     private IvySettings settings;
     
     private File basedir;
@@ -96,6 +98,8 @@
 
     private Long defaultTTL = null;
 
+    private ModuleDescriptorMemoryCache memoryModuleDescrCache;
+
     public DefaultRepositoryCacheManager() {
     }
 
@@ -228,7 +232,18 @@
                     parseDuration(duration));
     }
 
-
+    public void setMemorySize(int size) {
+        memoryModuleDescrCache = new ModuleDescriptorMemoryCache(size);
+    }
+    
+    public ModuleDescriptorMemoryCache getMemoryCache() {
+        if (memoryModuleDescrCache==null) {
+            memoryModuleDescrCache = new ModuleDescriptorMemoryCache(DEFAULT_MEMORY_CACHE_SIZE);
+        }
+        return memoryModuleDescrCache;
+    }
+    
+    
     private static final Pattern DURATION_PATTERN 
         = Pattern.compile("(?:(\\d+)d)? ?(?:(\\d+)h)? ?(?:(\\d+)m)? ?(?:(\\d+)s)? ?(?:(\\d+)ms)?");
 
@@ -542,8 +557,8 @@
             if (ivyFile.exists()) {
                 // found in cache !
                 try {
-                    ModuleDescriptor depMD = XmlModuleDescriptorParser.getInstance()
-                    .parseDescriptor(settings, ivyFile.toURI().toURL(), options.isValidate());
+                    XmlModuleDescriptorParser parser = XmlModuleDescriptorParser.getInstance();
+                    ModuleDescriptor depMD = getMdFromCache(parser, options, ivyFile);
                     String resolverName = getSavedResolverName(depMD);
                     String artResolverName = getSavedArtResolverName(depMD);
                     DependencyResolver resolver = settings.getResolver(resolverName);
@@ -603,6 +618,38 @@
         return null;
     }
 
+    
+    private class MyModuleDescriptorProvider implements ModuleDescriptorProvider {
+        
+        private final ModuleDescriptorParser mdParser;
+
+        public MyModuleDescriptorProvider(ModuleDescriptorParser mdParser) {
+            this.mdParser = mdParser;            
+        }
+        
+        public ModuleDescriptor provideModule(ParserSettings ivySettings, 
+                File descriptorURL, boolean validate) throws ParseException, IOException
{
+            return mdParser.parseDescriptor(ivySettings, descriptorURL.toURI().toURL(), validate);
+        }
+    }
+    
+    private ModuleDescriptor getMdFromCache(XmlModuleDescriptorParser mdParser, 
+            CacheMetadataOptions options, File ivyFile) 
+            throws ParseException, IOException, MalformedURLException {
+        ModuleDescriptorMemoryCache cache = getMemoryCache();
+        ModuleDescriptorProvider mdProvider = new MyModuleDescriptorProvider(mdParser); 
+        return cache.get(ivyFile, settings, options.isValidate(), mdProvider);
+    }
+
+    private ModuleDescriptor getStaledMd(ModuleDescriptorParser mdParser, 
+            CacheMetadataOptions options, File ivyFile) 
+            throws ParseException, IOException, MalformedURLException {
+        ModuleDescriptorMemoryCache cache = getMemoryCache();
+        ModuleDescriptorProvider mdProvider = new MyModuleDescriptorProvider(mdParser); 
+        return cache.getStale(ivyFile, settings, options.isValidate(), mdProvider);
+    }
+
+    
     private String getResolvedRevision(ModuleRevisionId mrid, CacheMetadataOptions options)
{
         if (!lockMetadataArtifact(mrid)) {
             Message.error("impossible to acquire lock for " + mrid);
@@ -887,17 +934,8 @@
                 return null;
             }
 
-            URL cachedMDURL = null;
-            try {
-                cachedMDURL = report.getLocalFile().toURI().toURL();
-            } catch (MalformedURLException ex) {
-                Message.warn("malformed url exception for original in cache file: " 
-                    + report.getLocalFile() + ": " + ex.getMessage());
-                return null;
-            }
             try {
-                ModuleDescriptor md = parser.parseDescriptor(
-                    settings, cachedMDURL, mdRef.getResource(), options.isValidate());
+                ModuleDescriptor md = getStaledMd(parser, options, report.getLocalFile());

                 if (md == null) {
                     throw new IllegalStateException(
                         "module descriptor parser returned a null module descriptor, " 

Added: ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCache.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCache.java?rev=685906&view=auto
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCache.java
(added)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCache.java
Thu Aug 14 07:11:20 2008
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.ivy.core.cache;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+
+import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
+import org.apache.ivy.plugins.parser.ParserSettings;
+import org.apache.ivy.util.Message;
+
+/**
+ * Cache ModuleDescriptors so that when the same module is used twice (in multi-module build
for 
+ * instance), it is parsed only once.
+ * This cache is has a limited size, and keep the most recently used entries.
+ * The entry in the cache are invalidated if there is a change to one variable
+ * used in the module descriptor.
+ */
+class ModuleDescriptorMemoryCache {
+
+    private final int maxSize;
+    private final LinkedHashMap/*<File,CacheEntry>*/ valueMap;
+    
+    
+    /**
+     * Create a cache of the given size
+     * @param size
+     */
+    public ModuleDescriptorMemoryCache(int size) {
+        this.maxSize = size;
+        this.valueMap = new LinkedHashMap(size);
+    }
+
+    public ModuleDescriptor get(File ivyFile, ParserSettings ivySettings, boolean validated,
+            ModuleDescriptorProvider mdProvider) throws ParseException, IOException {
+        
+        ModuleDescriptor descriptor = getFromCache(ivyFile, ivySettings, validated);
+        if (descriptor==null) {
+            descriptor = getStale(ivyFile, ivySettings, validated, mdProvider);
+        }
+        return descriptor;
+    }
+
+    /**
+     * Get the module descriptor from the mdProvider and store it into the cache. 
+     */
+    public ModuleDescriptor getStale(File ivyFile, ParserSettings ivySettings, boolean validated,
+            ModuleDescriptorProvider mdProvider) throws ParseException, IOException {
+        ParserSettingsMonitor settingsMonitor = new ParserSettingsMonitor(ivySettings);
+        ModuleDescriptor descriptor = mdProvider.provideModule(
+            settingsMonitor.getMonitoredSettings() , ivyFile, validated);
+        putInCache(ivyFile, settingsMonitor, validated, descriptor);
+        return descriptor;
+    }
+
+    ModuleDescriptor getFromCache(File ivyFile, ParserSettings ivySettings, boolean validated)
{
+        if (maxSize<=0) {
+            //cache is disbaled
+            return null;
+        }
+        CacheEntry entry = (CacheEntry) valueMap.get(ivyFile);
+        if (entry!=null) {
+            if (entry.isStale(validated, ivySettings)) {
+                Message.debug("Entry is found in the ModuleDescriptorCache but entry should
be " +
+                        "reevaluated : " + ivyFile);
+                valueMap.remove(ivyFile);
+                return null;
+            } else {
+                //Move the entry at the end of the list
+                valueMap.remove(ivyFile);
+                valueMap.put(ivyFile, entry);
+                Message.debug("Entry is found in the ModuleDescriptorCache : " + ivyFile);
+                return entry.md;
+            }
+        }
+        else {
+            Message.debug("No entry is found in the ModuleDescriptorCache : " + ivyFile);
+            return null;
+        }        
+    }
+
+    
+ 
+    void putInCache(File url, ParserSettingsMonitor ivySettingsMonitor, boolean validated,

+            ModuleDescriptor descriptor) {
+        if (maxSize<=0) {
+            //cache is disabled
+            return;
+        }
+        if (valueMap.size()>=maxSize) {
+            Message.debug("ModuleDescriptorCache is full, remove one entry");
+            Iterator it = valueMap.values().iterator();
+            it.next();
+            it.remove();
+        }
+        valueMap.put(url, new CacheEntry(descriptor , validated, ivySettingsMonitor));
+    }
+
+    
+    private static class CacheEntry {
+        final ModuleDescriptor md;
+        final boolean validated;
+        final ParserSettingsMonitor parserSettingsMonitor;
+
+        CacheEntry(ModuleDescriptor md ,boolean validated, ParserSettingsMonitor parserSettingsMonitor
) {
+            this.md = md;
+            this.validated = validated;
+            this.parserSettingsMonitor = parserSettingsMonitor;
+        }
+        
+        boolean isStale(boolean validated, ParserSettings newParserSettings) {
+            return (validated && !this.validated) || parserSettingsMonitor.hasChanged(newParserSettings);
+        }
+    }
+    
+}

Propchange: ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCache.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorProvider.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorProvider.java?rev=685906&view=auto
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorProvider.java (added)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorProvider.java Thu
Aug 14 07:11:20 2008
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.ivy.core.cache;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.ParseException;
+
+import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
+import org.apache.ivy.plugins.parser.ParserSettings;
+
+interface ModuleDescriptorProvider {
+
+    public ModuleDescriptor provideModule(ParserSettings ivySettings, File descriptorFile,
+            boolean validate) throws ParseException, IOException;
+}

Propchange: ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ModuleDescriptorProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ParserSettingsMonitor.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ParserSettingsMonitor.java?rev=685906&view=auto
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ParserSettingsMonitor.java (added)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ParserSettingsMonitor.java Thu Aug
14 07:11:20 2008
@@ -0,0 +1,138 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.ivy.core.cache;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.ivy.core.RelativeUrlResolver;
+import org.apache.ivy.core.module.id.ModuleRevisionId;
+import org.apache.ivy.core.module.status.StatusManager;
+import org.apache.ivy.plugins.conflict.ConflictManager;
+import org.apache.ivy.plugins.matcher.PatternMatcher;
+import org.apache.ivy.plugins.namespace.Namespace;
+import org.apache.ivy.plugins.parser.ParserSettings;
+import org.apache.ivy.plugins.resolver.DependencyResolver;
+import org.apache.ivy.util.Message;
+
+
+/**
+ * Keep traces of the usage of a ParserSettings in order to check afterwards that
+ * the relevant settings didn't changed.
+ * A ParserSettingsMonitor provide a ParserSettings that must be used in place of the
+ * orignal one.
+ * The current implementation consider that a settings changed iff one of the used variable
has changed.
+ */
+class ParserSettingsMonitor {
+
+    private ParserSettings delegatedSettings;
+    private final Map/*<String,String>*/ substitutes;
+    
+    
+    public ParserSettingsMonitor(ParserSettings settings) {
+        this.delegatedSettings = settings;
+        this.substitutes = new HashMap();
+    }
+    
+    /**
+     * @return The parser settings that must be used in place of the orignal settings
+     * The returned object delegates all the call to the original settings.
+     */
+    public ParserSettings getMonitoredSettings() {
+        return monitoredSettings;
+    }
+    
+    /**
+     * Free the ressource used during the monitoring, keeping only the info
+     * required to evaluate hasChanged.
+     */
+    public void endMonitoring() {
+        monitoredSettings = null;
+        delegatedSettings = null;
+    }
+    
+    /**
+     * Check if the newSettings is compatible with the original settings that
+     * has been monitored.  Only the info that was actually used is compared.
+     */
+    public boolean hasChanged(ParserSettings newSettings) {
+        for(Iterator it = substitutes.entrySet().iterator() ; it.hasNext() ;) {
+            Map.Entry entry = (Entry) it.next();
+            String key = (String) entry.getKey();
+            Object oldValue = entry.getValue();                
+            String newValue = newSettings.substitute(key);
+            if (! oldValue.equals(newValue)) {
+                Message.debug("settings variable has changed for : " + entry.getKey());
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    
+    private ParserSettings monitoredSettings = new ParserSettings() {
+
+        public ConflictManager getConflictManager(String name) {
+            return delegatedSettings.getConflictManager(name);
+        }
+
+        public PatternMatcher getMatcher(String matcherName) {
+            return delegatedSettings.getMatcher(matcherName);
+        }
+
+        public Namespace getNamespace(String namespace) {
+            return delegatedSettings.getNamespace(namespace);
+        }
+
+        public RelativeUrlResolver getRelativeUrlResolver() {
+            return delegatedSettings.getRelativeUrlResolver();
+        }
+
+        public ResolutionCacheManager getResolutionCacheManager() {
+            return delegatedSettings.getResolutionCacheManager();
+        }
+
+        public DependencyResolver getResolver(ModuleRevisionId mRevId) {
+            return delegatedSettings.getResolver(mRevId);
+        }
+
+        public StatusManager getStatusManager() {
+            return delegatedSettings.getStatusManager();
+        }
+
+        public Map substitute(Map strings) {
+            Map substituted = new LinkedHashMap();
+            for (Iterator it = strings.entrySet().iterator(); it.hasNext();) {
+                Map.Entry entry = (Map.Entry) it.next();
+                substituted.put(entry.getKey(), substitute((String) entry.getValue()));
+            }
+            return substituted;
+        }
+
+        public String substitute(String value) {
+            String r = delegatedSettings.substitute(value);
+            if (value!=null && value!=r) {
+                substitutes.put(value, r);
+            }
+            return r;
+        }
+    };
+}

Propchange: ant/ivy/core/trunk/src/java/org/apache/ivy/core/cache/ParserSettingsMonitor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/IvySettings.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/IvySettings.java?rev=685906&r1=685905&r2=685906&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/IvySettings.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/IvySettings.java Thu Aug 14 07:11:20
2008
@@ -576,6 +576,7 @@
      * @param str
      *            the string in which substitution should be made
      * @return the string where all current ivy variables have been substituted by their
value
+     *         If the input str doesn't use any variable, the same object is returned
      */
     public String substitute(String str) {
         return IvyPatternHelper.substituteVariables(str, variableContainer);

Added: ant/ivy/core/trunk/test/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCacheTest.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCacheTest.java?rev=685906&view=auto
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCacheTest.java
(added)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCacheTest.java
Thu Aug 14 07:11:20 2008
@@ -0,0 +1,167 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.ivy.core.cache;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.ParseException;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor;
+import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
+import org.apache.ivy.core.module.id.ModuleRevisionId;
+import org.apache.ivy.core.settings.IvySettings;
+import org.apache.ivy.plugins.parser.ParserSettings;
+
+public class ModuleDescriptorMemoryCacheTest extends TestCase {
+
+    ModuleDescriptorMemoryCache cache = new ModuleDescriptorMemoryCache(2);
+    ParserSettings ivySettings = new IvySettings();
+    IvySettings ivySettings2 = new IvySettings();
+    
+    File url1 = new File("file://cached/file.txt");;
+    File url2 = new File("file://cached/file2.txt");;
+    File url3 = new File("file://cached/file3.txt");;
+
+    ModuleRevisionId mrid1 = ModuleRevisionId.newInstance("org", "name", "rev");
+    ModuleDescriptor md1 = DefaultModuleDescriptor.newDefaultInstance(mrid1);
+    
+    ModuleRevisionId mrid2 = ModuleRevisionId.newInstance("org", "name", "rev2");
+    ModuleDescriptor md2 = DefaultModuleDescriptor.newDefaultInstance(mrid2);
+    
+    ModuleRevisionId mrid3 = ModuleRevisionId.newInstance("org", "name", "rev3");
+    ModuleDescriptor md3 = DefaultModuleDescriptor.newDefaultInstance(mrid3);
+        
+        
+    public void testUseModuleDescriptorProviderWhenModuleNotCached() throws ParseException,
IOException {
+        ModuleDescriptorProviderMock providerMock = new ModuleDescriptorProviderMock(md1);
+        assertEquals(md1 , cache.get(url1,ivySettings , false, providerMock));
+        providerMock.assertCalled();        
+    }
+    
+    
+    public void testCacheResultOfModuleDescriptorProvider() throws ParseException, IOException
{
+        ModuleDescriptorProviderMock providerMock = new ModuleDescriptorProviderMock(md1);
+        ModuleDescriptorProviderMock providerMock2 = null;
+        assertEquals(md1 , cache.get(url1,ivySettings , false, providerMock));
+        assertEquals(md1 , cache.get(url1,ivySettings , false, providerMock2));        
+    }
+    
+    
+    public void testValidationClearInvalidatedCache() throws ParseException, IOException
{
+        ModuleDescriptorProviderMock providerMock = new ModuleDescriptorProviderMock(md1);
+        ModuleDescriptorProviderMock providerMock2 = new ModuleDescriptorProviderMock(md1);;
+        assertEquals(md1 , cache.get(url1,ivySettings , false, providerMock));
+        assertEquals(md1 , cache.get(url1,ivySettings , true, providerMock2));
+        providerMock2.assertCalled();
+    }
+
+    
+    public void testValidationDontClearvalidatedCache() throws ParseException, IOException
{
+        ModuleDescriptorProviderMock providerMock = new ModuleDescriptorProviderMock(md1);
+        ModuleDescriptorProviderMock providerMock2 = null;
+        assertEquals(md1 , cache.get(url1,ivySettings , true, providerMock));
+        assertEquals(md1 , cache.get(url1,ivySettings , false, providerMock2));        
+    }
+
+   
+    public void testSizeIsLimitied() throws ParseException, IOException {
+        ModuleDescriptorProviderMock providerMock = new ModuleDescriptorProviderMock(md1);
+        ModuleDescriptorProviderMock providerMock1b = new ModuleDescriptorProviderMock(md1);
+        ModuleDescriptorProviderMock providerMock2 = new ModuleDescriptorProviderMock(md2);
+        ModuleDescriptorProviderMock providerMock3 = new ModuleDescriptorProviderMock(md3);
+        cache.get(url1,ivySettings , false, providerMock);
+        cache.get(url2,ivySettings , false, providerMock2);
+        cache.get(url3,ivySettings , false, providerMock3);//adding 1
+        cache.get(url1,ivySettings , false, providerMock1b);//and one has been removed
+        providerMock1b.assertCalled();
+    }
+
+    public void testLastRecentlyUsedIsFlushedWhenSizeExceed() throws ParseException, IOException
{
+        ModuleDescriptorProviderMock providerMock = new ModuleDescriptorProviderMock(md1);
+        ModuleDescriptorProviderMock providerMock2 = new ModuleDescriptorProviderMock(md2);
+        ModuleDescriptorProviderMock providerMock2b = new ModuleDescriptorProviderMock(md1);
+        ModuleDescriptorProviderMock providerMock3 = new ModuleDescriptorProviderMock(md3);
+        cache.get(url1,ivySettings , false, providerMock);
+        cache.get(url2,ivySettings , false, providerMock2);
+        cache.get(url1,ivySettings , false, null);  
+        cache.get(url3,ivySettings , false, providerMock3);
+        cache.get(url1,ivySettings , false, null);//and one has been removed
+        cache.get(url2,ivySettings , false, providerMock2b);
+        providerMock2b.assertCalled();
+    }
+
+
+    public void testVariableChangeInvalidateEntry() throws ParseException, IOException {
+        ModuleDescriptorProviderMock providerMock = new ModuleDescriptorProviderMock(md1);
+        ModuleDescriptorProviderMock providerMock2 = new ModuleDescriptorProviderMock(md1);
+        assertEquals(md1 , cache.get(url1,ivySettings2 , false, providerMock));
+        ivySettings2.getVariables().setVariable("val", "changedVal", true);
+        assertEquals(md1 , cache.get(url1,ivySettings2 , false, providerMock2));
+        providerMock2.assertCalled();
+    }
+    
+    
+    public void testGetStaleDontReadFromCache() throws ParseException, IOException {
+        ModuleDescriptorProviderMock providerMock = new ModuleDescriptorProviderMock(md1);
+        ModuleDescriptorProviderMock providerMock2 = new ModuleDescriptorProviderMock(md2);
+        assertEquals(md1 , cache.get(url1,ivySettings , false, providerMock));
+        assertEquals(md2 , cache.getStale(url1,ivySettings , false, providerMock2));
+        providerMock2.assertCalled();        
+    }
+    
+    public void testGetStaleStoreResultInCache() throws ParseException, IOException {
+        ModuleDescriptorProviderMock providerMock = new ModuleDescriptorProviderMock(md1);
+        ModuleDescriptorProviderMock providerMock2 = null;
+        assertEquals(md1 , cache.getStale(url1,ivySettings , false, providerMock));
+        assertEquals(md1 , cache.get(url1,ivySettings , false, providerMock2));        
+    }
+    
+    public void testASizeOf0MeansNoCache() throws ParseException, IOException {
+        cache = new ModuleDescriptorMemoryCache(0);
+        ModuleDescriptorProviderMock providerMock = new ModuleDescriptorProviderMock(md1);
+        ModuleDescriptorProviderMock providerMock2 = new ModuleDescriptorProviderMock(md1);
+        assertEquals(md1 , cache.get(url1,ivySettings , false, providerMock));
+        assertEquals(md1 , cache.get(url1,ivySettings , false, providerMock2));
+        providerMock2.assertCalled();
+    }
+    
+    private static class ModuleDescriptorProviderMock implements ModuleDescriptorProvider
{
+        
+        private boolean called = false;
+        private final ModuleDescriptor result;
+        
+        public ModuleDescriptorProviderMock(ModuleDescriptor result) {
+            this.result = result;
+        }
+
+        public ModuleDescriptor provideModule(ParserSettings ivySettings, File descriptorFile,

+                boolean validate) {
+            if (ivySettings!=null) ivySettings.substitute("${val}");
+            called = true;
+            return result;
+        }
+        
+        public void assertCalled() {
+            Assert.assertTrue(called);
+        }
+    }
+    
+}

Propchange: ant/ivy/core/trunk/test/java/org/apache/ivy/core/cache/ModuleDescriptorMemoryCacheTest.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message