blob: 3b1fcfa141db31d193456e29c6a988e74ad8557e [file] [log] [blame]
/*
* 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
*
* https://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 org.apache.ivy.core.module.descriptor.ModuleDescriptor;
import org.apache.ivy.plugins.parser.ParserSettings;
import org.apache.ivy.util.Message;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.Iterator;
import java.util.LinkedHashMap;
/**
* 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 int
*/
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 disabled
return null;
}
synchronized (valueMap) {
CacheEntry entry = valueMap.get(ivyFile);
if (entry != null) {
if (entry.isStale(ivyFile, 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;
}
synchronized (valueMap) {
if (valueMap.size() >= maxSize) {
Message.debug("ModuleDescriptorCache is full, remove one entry");
Iterator<CacheEntry> it = valueMap.values().iterator();
it.next();
it.remove();
}
valueMap.put(url, new CacheEntry(descriptor, validated, ivySettingsMonitor));
}
}
private static class CacheEntry {
private final ModuleDescriptor md;
private final boolean validated;
private final ParserSettingsMonitor parserSettingsMonitor;
CacheEntry(ModuleDescriptor md, boolean validated,
ParserSettingsMonitor parserSettingsMonitor) {
this.md = md;
this.validated = validated;
this.parserSettingsMonitor = parserSettingsMonitor;
}
boolean isStale(File ivyFile, boolean validated, ParserSettings newParserSettings) {
return (validated && !this.validated)
|| md.getLastModified() != ivyFile.lastModified()
|| parserSettingsMonitor.hasChanged(newParserSettings);
}
}
}