/* * * Copyright (C) 2010 JFrog Ltd. * * Licensed 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.jfrog.wharf.ivy.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 */ 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 { 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(boolean validated, ParserSettings newParserSettings) { return (validated && !this.validated) || parserSettingsMonitor.hasChanged(newParserSettings); } } }