Skip to content

Commit 91c4348

Browse files
committed
🆕 Refactor configuration mechanism out of org.spdx.library.model.license.ListedLicenses and make it generic
1 parent ea5d61b commit 91c4348

3 files changed

Lines changed: 126 additions & 47 deletions

File tree

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* Copyright (c) 2023 Source Auditor Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.spdx;
19+
20+
import java.io.IOException;
21+
import java.io.InputStream;
22+
import java.util.Properties;
23+
24+
import org.slf4j.Logger;
25+
import org.slf4j.LoggerFactory;
26+
27+
/**
28+
* A configuration class for the Spdx-Java-Library. When a caller attempts to retrieve a configuration property, it
29+
* will first be checked in the Java system properties (i.e. set via `-D` command line options to the JVM, or by
30+
* programmatic calls to `System.setProperty()` in code), and will then fallback on a properties file in the classpath.
31+
* That file must be called `/resources/spdx-java-library.properties`.
32+
*/
33+
public final class Configuration {
34+
private static final Logger logger = LoggerFactory.getLogger(Configuration.class.getName());
35+
private static final String PROPERTIES_DIR = "resources";
36+
private static final String CONFIGURATION_PROPERTIES_FILENAME = PROPERTIES_DIR + "/" + "spdx-java-library.properties";
37+
private static final String DEPRECATED_CONFIGURATION_PROPERTIES_FILENAME = PROPERTIES_DIR + "/" + "licenses.properties"; // Deprecated filename
38+
39+
private static Configuration singleton;
40+
private final Properties properties;
41+
42+
private Configuration() {
43+
Properties tmpProperties = loadProperties(CONFIGURATION_PROPERTIES_FILENAME);
44+
if (tmpProperties == null) {
45+
tmpProperties = loadProperties(DEPRECATED_CONFIGURATION_PROPERTIES_FILENAME);
46+
if (tmpProperties != null) {
47+
logger.warn("You are using a deprecated property filename ('" + DEPRECATED_CONFIGURATION_PROPERTIES_FILENAME + "'). Please consider migrating to the new name ('" + CONFIGURATION_PROPERTIES_FILENAME + "').");
48+
}
49+
}
50+
properties = tmpProperties;
51+
}
52+
53+
/**
54+
* @return The singleton instance of the Configuration class.
55+
*/
56+
public static Configuration getInstance() {
57+
if (singleton == null) {
58+
singleton = new Configuration();
59+
}
60+
return singleton;
61+
}
62+
63+
/**
64+
* @param propertyName The name of the configuration property to retrieve.
65+
* @return The value of the given property name, or null if it wasn't found.
66+
*/
67+
public String getProperty(final String propertyName) {
68+
return getProperty(propertyName, null);
69+
}
70+
71+
/**
72+
* @param propertyName The name of the configuration property to retrieve.
73+
* @param defaultValue The default value to return, if the property isn't found.
74+
* @return The value of the given property name, or defaultValue if it wasn't found.
75+
*/
76+
public String getProperty(final String propertyName, final String defaultValue) {
77+
return System.getProperty(propertyName, properties == null ? defaultValue : properties.getProperty(propertyName, defaultValue));
78+
}
79+
80+
/**
81+
* Tries to load properties from the CLASSPATH, using the provided filename, ignoring errors
82+
* encountered during the process (e.g., the properties file doesn't exist, etc.).
83+
*
84+
* @param propertiesFileName the name of the file to load, including path (if any)
85+
* @return a (possibly empty) set of properties
86+
*/
87+
private static Properties loadProperties(final String propertiesFileName) {
88+
Properties result = null;
89+
if (propertiesFileName != null) {
90+
InputStream in = null;
91+
try {
92+
in = Configuration.class.getResourceAsStream("/" + propertiesFileName);
93+
if (in != null) {
94+
result = new Properties();
95+
result.load(in);
96+
}
97+
} catch (IOException e) {
98+
// Ignore it and fall through
99+
logger.warn("IO Exception reading configuration properties file '" + propertiesFileName + "': " + e.getMessage(), e);
100+
} finally {
101+
if (in != null) {
102+
try {
103+
in.close();
104+
} catch (IOException e) {
105+
// Ignore it and fall through
106+
logger.warn("Unable to close configuration properties file '" + propertiesFileName + "': " + e.getMessage(), e);
107+
}
108+
}
109+
}
110+
}
111+
return result;
112+
}
113+
114+
}

src/main/java/org/spdx/library/model/license/ListedLicenses.java

Lines changed: 7 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import org.slf4j.Logger;
3030
import org.slf4j.LoggerFactory;
31+
import org.spdx.Configuration;
3132
import org.spdx.library.InvalidSPDXAnalysisException;
3233
import org.spdx.library.SpdxConstants;
3334
import org.spdx.library.model.SpdxModelFactory;
@@ -45,10 +46,7 @@
4546
public class ListedLicenses {
4647

4748
static final Logger logger = LoggerFactory.getLogger(ListedLicenses.class.getName());
48-
private static final String PROPERTIES_DIR = "resources";
49-
private static final String LISTED_LICENSE_PROPERTIES_FILENAME = PROPERTIES_DIR + "/" + "licenses.properties";
5049

51-
Properties licenseProperties;
5250
boolean onlyUseLocalLicenses;
5351
private IListedLicenseStore licenseModelStore;
5452
private static ListedLicenses listedLicenses = null;
@@ -61,46 +59,14 @@ public class ListedLicenses {
6159
* This constructor should only be called by the getListedLicenses method
6260
*/
6361
private ListedLicenses() {
64-
licenseProperties = loadLicenseProperties();
65-
onlyUseLocalLicenses = Boolean.parseBoolean(
66-
System.getProperty("SPDXParser.OnlyUseLocalLicenses", licenseProperties.getProperty("OnlyUseLocalLicenses", "false")));
62+
// Note: this code confusingly uses different property values depending on the source (Java system property vs properties file),
63+
// so we have to check both names in order to not break downstream consumers' legacy configurations. This is _NOT_ recommended for
64+
// any new code that leverages the Configuration class.
65+
onlyUseLocalLicenses = Boolean.parseBoolean(Configuration.getInstance().getProperty("SPDXParser.OnlyUseLocalLicenses",
66+
Configuration.getInstance().getProperty("OnlyUseLocalLicenses", "false")));
6767
initializeLicenseModelStore();
6868
}
69-
70-
/**
71-
* Tries to load properties from LISTED_LICENSE_PROPERTIES_FILENAME, ignoring errors
72-
* encountered during the process (e.g., the properties file doesn't exist, etc.).
73-
*
74-
* @return a (possibly empty) set of properties
75-
*/
76-
private static Properties loadLicenseProperties() {
77-
listedLicenseModificationLock.writeLock().lock();
78-
try {
79-
Properties licenseProperties = new Properties();
80-
InputStream in = null;
81-
try {
82-
in = ListedLicenses.class.getResourceAsStream("/" + LISTED_LICENSE_PROPERTIES_FILENAME);
83-
if (in != null) {
84-
licenseProperties.load(in);
85-
}
86-
} catch (IOException e) {
87-
// Ignore it and fall through
88-
logger.warn("IO Exception reading listed license properties file: " + e.getMessage());
89-
} finally {
90-
if (in != null) {
91-
try {
92-
in.close();
93-
} catch (IOException e) {
94-
logger.warn("Unable to close listed license properties file: " + e.getMessage());
95-
}
96-
}
97-
}
98-
return licenseProperties;
99-
} finally {
100-
listedLicenseModificationLock.writeLock().unlock();
101-
}
102-
}
103-
69+
10470
private void initializeLicenseModelStore() {
10571
listedLicenseModificationLock.writeLock().lock();
10672
try {
@@ -125,8 +91,6 @@ private void initializeLicenseModelStore() {
12591
}
12692
}
12793

128-
129-
13094
public static ListedLicenses getListedLicenses() {
13195

13296
ListedLicenses retval = null;

src/main/java/org/spdx/storage/listedlicense/SpdxListedLicenseWebStore.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import com.google.gson.reflect.TypeToken;
5151
import org.slf4j.Logger;
5252
import org.slf4j.LoggerFactory;
53+
import org.spdx.Configuration;
5354
import org.spdx.library.InvalidSPDXAnalysisException;
5455
import org.spdx.library.SpdxConstants;
5556

@@ -76,8 +77,8 @@ public class SpdxListedLicenseWebStore extends SpdxListedLicenseModelStore {
7677
System.getenv("XDG_CACHE_HOME")) +
7778
File.separator + "Spdx-Java-Library";
7879

79-
private final String JAVA_PROPERTY_CACHE_ENABLED = "org.spdx.storage.listedlicense.enableCache";
80-
private final String JAVA_PROPERTY_CACHE_CHECK_INTERVAL_SECS = "org.spdx.storage.listedlicense.cacheCheckIntervalSecs";
80+
private final String CONFIG_PROPERTY_CACHE_ENABLED = "org.spdx.storage.listedlicense.enableCache";
81+
private final String CONFIG_PROPERTY_CACHE_CHECK_INTERVAL_SECS = "org.spdx.storage.listedlicense.cacheCheckIntervalSecs";
8182
private final boolean cacheEnabled;
8283
private final long cacheCheckIntervalSecs;
8384

@@ -90,7 +91,7 @@ public SpdxListedLicenseWebStore() throws InvalidSPDXAnalysisException {
9091
super();
9192

9293
// Initialise cache
93-
boolean tmpCacheEnabled = Boolean.parseBoolean(System.getProperty(JAVA_PROPERTY_CACHE_ENABLED));
94+
boolean tmpCacheEnabled = Boolean.parseBoolean(Configuration.getInstance().getProperty(CONFIG_PROPERTY_CACHE_ENABLED, "false"));
9495
if (tmpCacheEnabled) {
9596
try {
9697
final File cacheDirectory = new File(cacheDir);
@@ -103,7 +104,7 @@ public SpdxListedLicenseWebStore() throws InvalidSPDXAnalysisException {
103104
cacheEnabled = tmpCacheEnabled;
104105
long tmpCacheCheckIntervalSecs = DEFAULT_CACHE_CHECK_INTERVAL_SECS;
105106
try {
106-
tmpCacheCheckIntervalSecs = Long.parseLong(System.getProperty(JAVA_PROPERTY_CACHE_CHECK_INTERVAL_SECS));
107+
tmpCacheCheckIntervalSecs = Long.parseLong(Configuration.getInstance().getProperty(CONFIG_PROPERTY_CACHE_CHECK_INTERVAL_SECS));
107108
} catch(NumberFormatException nfe) {
108109
// Ignore parse failures - in this case we use the default value of 24 hours
109110
}

0 commit comments

Comments
 (0)