Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
*/
package org.owasp.dependencycheck.data.cache;

import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.jcs3.access.CacheAccess;
import org.apache.commons.jcs3.engine.behavior.ICacheElement;
import org.apache.commons.jcs3.engine.behavior.IElementAttributes;

/**
* A generic wrapper for the Java Caching System (JCS).
Expand All @@ -32,6 +35,10 @@ public class DataCache<T> {
* A reference to the JCS cache.
*/
private final CacheAccess<String, T> cache;
/**
* The intended policy configured for the cache region; for reconciling to existing elements with legacy configuration
*/
private final IElementAttributes regionAttributes;

/**
* Creates a new generic JCS wrapper.
Expand All @@ -40,6 +47,7 @@ public class DataCache<T> {
*/
DataCache(CacheAccess<String, T> cache) {
this.cache = cache;
this.regionAttributes = cache.getDefaultElementAttributes();
}

/**
Expand All @@ -49,7 +57,38 @@ public class DataCache<T> {
* @return the cached object
*/
public T get(String key) {
return cache.get(key);
final ICacheElement<String, T> element = cache.getCacheElement(key);
if (element == null) {
return null;
}
if (!regionAttributes.getIsEternal() && element.getElementAttributes().getIsEternal()) {
return repairToNonEternal(element);
}
return element.getVal();
}

/**
* Releases configured before 13.0.1 accidentally configured the cache regions such that elements were persisted
* to disk as eternal, so JCS would never expire them according to intended policy.
* This resets the element's attributes to the region's current expiry policy while retaining its
* original creation time: an element that is still within its lifetime is kept (and re-persisted with corrected
* attributes so that JCS manages its expiry from here on) rather than being discarded and re-fetched, while an
* element that has outlived the policy is removed.
*
* @param element the eternal element retrieved from the cache
* @return the cached object if it is still within its lifetime; otherwise {@code null}
*/
private T repairToNonEternal(ICacheElement<String, T> element) {
final IElementAttributes attributes = element.getElementAttributes();
attributes.setIsEternal(regionAttributes.getIsEternal());
attributes.setMaxLife(regionAttributes.getMaxLife());
attributes.setIdleTime(regionAttributes.getIdleTime());
if (cache.getCacheControl().isExpired(element)) {
cache.remove(element.getKey());
return null;
}
cache.put(element.getKey(), element.getVal(), attributes);
return element.getVal();
}

/**
Expand All @@ -61,4 +100,9 @@ public T get(String key) {
public void put(String key, T content) {
cache.put(key, content);
}

@VisibleForTesting
void put(String key, T content, IElementAttributes attributes) {
cache.put(key, content, attributes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@
package org.owasp.dependencycheck.data.cache;

import io.github.jeremylong.jcs3.slf4j.Slf4jAdapter;
import io.github.jeremylong.jcs3.slf4j.Slf4jLogFactory;
import org.apache.commons.jcs3.JCS;
import org.apache.commons.jcs3.access.CacheAccess;
import org.apache.commons.jcs3.access.exception.CacheException;
import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
import org.owasp.dependencycheck.data.nodeaudit.Advisory;
import org.owasp.dependencycheck.utils.FileUtils;
Expand Down Expand Up @@ -79,10 +77,36 @@ private enum CacheType {
POM
}

static {
System.setProperty("jcs.logSystem", "slf4j");
if (!LOGGER.isTraceEnabled()) {
Slf4jAdapter.muteLogging(true);
private static synchronized void ensureInitialized(Settings settings) {
if (!initialized) {
JCS.setLogSystem(new Slf4jLogFactory().getName());
if (!LOGGER.isTraceEnabled()) {
Slf4jAdapter.muteLogging(true);
}

final File cacheDirectory;
try {
cacheDirectory = new File(settings.getDataDirectory(), CACHE_DIRECTORY);
} catch (IOException ex) {
throw new CacheException("Unable to obtain disk cache directory path", ex);
}
if (!cacheDirectory.isDirectory() && !cacheDirectory.mkdirs()) {
throw new CacheException("Unable to create disk cache: " + cacheDirectory);
}
try (InputStream in = FileUtils.getResourceAsStream(CACHE_PROPERTIES)) {
final Properties properties = new Properties();
properties.load(in);
properties.put("jcs.auxiliary.ODC.attributes.DiskPath", cacheDirectory.getCanonicalPath());
for (CacheType t : CacheType.values()) {
final File fp = new File(cacheDirectory, t.toString());
properties.put("jcs.auxiliary." + t + ".attributes.DiskPath", fp.getCanonicalPath());
}

JCS.setConfigProperties(properties);
initialized = true;
} catch (IOException ex) {
throw new CacheException("Error creating disk cache", ex);
}
}
}

Expand All @@ -92,33 +116,7 @@ private enum CacheType {
* @param settings the configuration settings
*/
public DataCacheFactory(Settings settings) {
synchronized (DataCacheFactory.class) {
if (!initialized) {
final File cacheDirectory;
try {
cacheDirectory = new File(settings.getDataDirectory(), CACHE_DIRECTORY);
} catch (IOException ex) {
throw new CacheException("Unable to obtain disk cache directory path", ex);
}
if (!cacheDirectory.isDirectory() && !cacheDirectory.mkdirs()) {
throw new CacheException("Unable to create disk cache: " + cacheDirectory);
}
try (InputStream in = FileUtils.getResourceAsStream(CACHE_PROPERTIES)) {
final Properties properties = new Properties();
properties.load(in);
properties.put("jcs.auxiliary.ODC.attributes.DiskPath", cacheDirectory.getCanonicalPath());
for (CacheType t : CacheType.values()) {
final File fp = new File(cacheDirectory, t.toString());
properties.put("jcs.auxiliary." + t + ".attributes.DiskPath", fp.getCanonicalPath());
}

JCS.setConfigProperties(properties);
initialized = true;
} catch (IOException ex) {
throw new CacheException("Error creating disk cache", ex);
}
}
}
ensureInitialized(settings);
}

/**
Expand All @@ -128,13 +126,7 @@ public DataCacheFactory(Settings settings) {
*/
public DataCache<List<Advisory>> getNodeAuditCache() {
try {
final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
attr.setUseDisk(true);
attr.setUseLateral(false);
attr.setUseRemote(false);
final CacheAccess<String, List<Advisory>> ca = JCS.getInstance("NODEAUDIT", attr);
final DataCache<List<Advisory>> dc = new DataCache<>(ca);
return dc;
return new DataCache<>(JCS.getInstance("NODEAUDIT"));
} catch (Throwable ex) {
//some reports of class not found exception, log and disable the cache.
if (ex instanceof CacheException) {
Expand All @@ -152,13 +144,7 @@ public DataCache<List<Advisory>> getNodeAuditCache() {
*/
public DataCache<Model> getPomCache() {
try {
final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
attr.setUseDisk(true);
attr.setUseLateral(false);
attr.setUseRemote(false);
final CacheAccess<String, Model> ca = JCS.getInstance("POM", attr);
final DataCache<Model> dc = new DataCache<>(ca);
return dc;
return new DataCache<>(JCS.getInstance("POM"));
} catch (Throwable ex) {
//some reports of class not found exception, log and disable the cache.
if (ex instanceof CacheException) {
Expand All @@ -176,13 +162,7 @@ public DataCache<Model> getPomCache() {
*/
public DataCache<List<MavenArtifact>> getCentralCache() {
try {
final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
attr.setUseDisk(true);
attr.setUseLateral(false);
attr.setUseRemote(false);
final CacheAccess<String, List<MavenArtifact>> ca = JCS.getInstance("CENTRAL", attr);
final DataCache<List<MavenArtifact>> dc = new DataCache<>(ca);
return dc;
return new DataCache<>(JCS.getInstance("CENTRAL"));
} catch (Throwable ex) {
//some reports of class not found exception, log and disable the cache.
if (ex instanceof CacheException) {
Expand Down
52 changes: 13 additions & 39 deletions core/src/main/resources/dependencycheck-cache.properties
Original file line number Diff line number Diff line change
@@ -1,57 +1,31 @@
# DEFAULT CACHE REGION
# DEFAULT CACHE REGION (all other caches inherit these values)
jcs.default=ODC
jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.default.cacheattributes.UseMemoryShrinker=false
jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.default.elementattributes.IsEternal=false
# use zero max objects with an update pattern to force disk caching
# use zero max objects with an update pattern to force disk-only caching since creation (no memory cache)
jcs.default.cacheattributes.MaxObjects=0
jcs.default.cacheattributes.DiskUsagePattern=UPDATE
#24 hour default cache life
jcs.default.cacheattributes.UseDisk=true
jcs.default.cacheattributes.UseRemote=false
jcs.default.cacheattributes.UseLateral=false

#24 hour default cache life, no idle expiry since access time isn't updated using disk-only caches
jcs.default.elementattributes.MaxLife=86400
jcs.default.elementattributes.IdleTime=1800
jcs.default.elementattributes.IdleTime=-1
jcs.default.elementattributes.IsEternal=false
jcs.default.elementattributes.IsSpool=true
jcs.default.elementattributes.IsRemote=false
jcs.default.elementattributes.IsLateral=false
jcs.default.elementattributes.IsRemote=false

#note - some region attributes are defined at load tiem in the DataCacheFactory.
#30 day cache life for main Central SHA1 search results
jcs.region.CENTRAL=ODC
jcs.region.CENTRAL.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.CENTRAL.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.CENTRAL.cacheattributes.MaxObjects=0
jcs.region.CENTRAL.cacheattributes.DiskUsagePattern=UPDATE
#30 day cache life for Central
jcs.region.CENTRAL.elementattributes.MaxLife=2592000
jcs.region.CENTRAL.elementattributes.IsSpool=true
jcs.region.CENTRAL.elementattributes.IsRemote=false
jcs.region.CENTRAL.elementattributes.IsLateral=false

#note - some region attributes are defined at load tiem in the DataCacheFactory.
#90 day cache life for POM files from Central
jcs.region.POM=ODC
jcs.region.POM.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.POM.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.POM.cacheattributes.MaxObjects=0
jcs.region.POM.cacheattributes.DiskUsagePattern=UPDATE
#90 day cache life for POM files from Central - this should likely be higher...
jcs.region.POM.elementattributes.MaxLife=7776000
jcs.region.POM.elementattributes.IsSpool=true
jcs.region.POM.elementattributes.IsRemote=false
jcs.region.POM.elementattributes.IsLateral=false


#24 hour default cache life for Node Audit
jcs.region.NODEAUDIT=ODC
jcs.region.NODEAUDIT.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.NODEAUDIT.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes
jcs.region.NODEAUDIT.cacheattributes.MaxObjects=0
jcs.region.NODEAUDIT.cacheattributes.DiskUsagePattern=UPDATE
#24 hour default cache life
jcs.region.NODEAUDIT.elementattributes.MaxLife=86400
jcs.region.NODEAUDIT.elementattributes.IsSpool=true
jcs.region.NODEAUDIT.elementattributes.IsRemote=false
jcs.region.NODEAUDIT.elementattributes.IsLateral=false

# AVAILABLE AUXILIARY CACHES
jcs.auxiliary.ODC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
Expand Down
Loading
Loading