diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/Settings.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/Settings.java
index 69cad756b..94f5b8ab8 100644
--- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/Settings.java
+++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/utils/Settings.java
@@ -42,6 +42,7 @@ public final class Settings {
* The logger.
*/
private static final Logger LOGGER = Logger.getLogger(Settings.class.getName());
+ //
/**
* The collection of keys used within the properties file.
@@ -198,18 +199,21 @@ public final class Settings {
*/
public static final String SKIP_PROVIDED_SCOPE = "skip.provided.scope";
}
+ //
+
/**
* The properties file location.
*/
private static final String PROPERTIES_FILE = "dependencycheck.properties";
- /**
- * The singleton instance variable.
- */
- private static final Settings INSTANCE = new Settings();
+
/**
* The properties.
*/
private Properties props = null;
+ /**
+ * Thread local settings.
+ */
+ private static ThreadLocal THREAD_LOCAL = new ThreadLocal();
/**
* Private constructor for the Settings class. This class loads the properties files.
@@ -235,6 +239,25 @@ public final class Settings {
logProperties("Properties loaded", props);
}
+ /**
+ * Initializes the thread local settings object. Note, to use the settings object you must call this method.
+ * However, you must also call Settings.cleanup() to properly release resources.
+ */
+ public static void initialize() {
+ THREAD_LOCAL.set(new Settings());
+ }
+
+ /**
+ * Cleans up resources to prevent memory leaks.
+ */
+ public static void cleanup() {
+ try {
+ THREAD_LOCAL.remove();
+ } catch (Throwable ex) {
+ LOGGER.log(Level.FINE, "Error cleaning up Settings", ex);
+ }
+ }
+
/**
* Logs the properties. This will not log any properties that contain 'password' in the key.
*
@@ -278,7 +301,7 @@ public final class Settings {
* @param value the value for the property
*/
public static void setString(String key, String value) {
- INSTANCE.props.setProperty(key, value);
+ THREAD_LOCAL.get().props.setProperty(key, value);
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine(String.format("Setting: %s='%s'", key, value));
}
@@ -292,9 +315,9 @@ public final class Settings {
*/
public static void setBoolean(String key, boolean value) {
if (value) {
- INSTANCE.props.setProperty(key, Boolean.TRUE.toString());
+ THREAD_LOCAL.get().props.setProperty(key, Boolean.TRUE.toString());
} else {
- INSTANCE.props.setProperty(key, Boolean.FALSE.toString());
+ THREAD_LOCAL.get().props.setProperty(key, Boolean.FALSE.toString());
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine(String.format("Setting: %s='%b'", key, value));
@@ -338,8 +361,8 @@ public final class Settings {
* @throws IOException is thrown when there is an exception loading/merging the properties
*/
public static void mergeProperties(InputStream stream) throws IOException {
- INSTANCE.props.load(stream);
- logProperties("Properties updated via merge", INSTANCE.props);
+ THREAD_LOCAL.get().props.load(stream);
+ logProperties("Properties updated via merge", THREAD_LOCAL.get().props);
}
/**
@@ -419,7 +442,7 @@ public final class Settings {
* @return the property from the properties file
*/
public static String getString(String key, String defaultValue) {
- final String str = System.getProperty(key, INSTANCE.props.getProperty(key, defaultValue));
+ final String str = System.getProperty(key, THREAD_LOCAL.get().props.getProperty(key, defaultValue));
return str;
}
@@ -441,7 +464,7 @@ public final class Settings {
* @return the property from the properties file
*/
public static String getString(String key) {
- return System.getProperty(key, INSTANCE.props.getProperty(key));
+ return System.getProperty(key, THREAD_LOCAL.get().props.getProperty(key));
}
/**
@@ -450,7 +473,7 @@ public final class Settings {
* @param key the property key to remove
*/
public static void removeProperty(String key) {
- INSTANCE.props.remove(key);
+ THREAD_LOCAL.get().props.remove(key);
}
/**