Skip to content

Commit 125895c

Browse files
author
Benny Bottema
committed
#538: fix how System properties and Environment properties are loaded, in the absence of a properties file (also env properties were loading incorrectly)
1 parent 49b6359 commit 125895c

File tree

3 files changed

+150
-93
lines changed

3 files changed

+150
-93
lines changed

Diff for: modules/core-module/src/main/java/org/simplejavamail/config/ConfigLoader.java

+44-63
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
import org.slf4j.Logger;
1111
import org.slf4j.LoggerFactory;
1212

13-
import java.io.File;
14-
import java.io.FileInputStream;
15-
import java.io.FileNotFoundException;
1613
import java.io.IOException;
1714
import java.io.InputStream;
1815
import java.util.HashMap;
@@ -106,7 +103,7 @@
106103
public final class ConfigLoader {
107104

108105
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigLoader.class);
109-
106+
110107
/**
111108
* By default, the optional file {@value} will be loaded from classpath to load initial defaults.
112109
*/
@@ -131,7 +128,7 @@ public final class ConfigLoader {
131128
// RESOLVED_PROPERTIES = loadProperties(DEFAULT_CONFIG_FILENAME); <-- not possible
132129
loadProperties(DEFAULT_CONFIG_FILENAME, false);
133130
}
134-
131+
135132
/**
136133
* List of all the properties recognized by Simple Java Mail. Can be used to programmatically get, set or remove default values.
137134
*
@@ -217,10 +214,10 @@ public String key() {
217214
return key;
218215
}
219216
}
220-
217+
221218
private ConfigLoader() {
222219
}
223-
220+
224221
/**
225222
* @return The value if not null or else the value from config file if provided or else <code>null</code>.
226223
*/
@@ -236,23 +233,23 @@ public static <T> T valueOrProperty(final @Nullable T value, final Property prop
236233
public static String valueOrPropertyAsString(@Nullable final String value, @NotNull final Property property, @Nullable final String defaultValue) {
237234
return SimpleConversions.convertToString(valueOrProperty(value, property, defaultValue));
238235
}
239-
236+
240237
/**
241238
* See {@link #valueOrProperty(Object, Property, Object)}.
242239
*/
243240
@Nullable
244241
public static Boolean valueOrPropertyAsBoolean(@Nullable final Boolean value, @NotNull final Property property, @Nullable final Boolean defaultValue) {
245242
return SimpleConversions.convertToBoolean(valueOrProperty(value, property, defaultValue));
246243
}
247-
244+
248245
/**
249246
* See {@link #valueOrProperty(Object, Property, Object)}.
250247
*/
251248
@Nullable
252249
public static Integer valueOrPropertyAsInteger(@Nullable final Integer value, @NotNull final Property property, @Nullable final Integer defaultValue) {
253250
return SimpleConversions.convertToInteger(valueOrProperty(value, property, defaultValue));
254251
}
255-
252+
256253
/**
257254
* Returns the given value if not null and not empty, otherwise tries to resolve the given property and if still not found resort to the default value if
258255
* provided.
@@ -279,13 +276,13 @@ public static <T> T valueOrProperty(@Nullable final T value, @NotNull final Prop
279276
public static synchronized boolean hasProperty(final Property property) {
280277
return !valueNullOrEmpty(RESOLVED_PROPERTIES.get(property));
281278
}
282-
279+
283280
@SuppressWarnings("unchecked")
284281
@Nullable
285282
public static synchronized <T> T getProperty(final Property property) {
286283
return (T) RESOLVED_PROPERTIES.get(property);
287284
}
288-
285+
289286
@Nullable
290287
public static synchronized String getStringProperty(final Property property) {
291288
return SimpleConversions.convertToString(RESOLVED_PROPERTIES.get(property));
@@ -312,10 +309,12 @@ public static synchronized Boolean getBooleanProperty(final Property property) {
312309
public static Map<Property, Object> loadProperties(final String filename, final boolean addProperties) {
313310
final InputStream input = ConfigLoader.class.getClassLoader().getResourceAsStream(filename);
314311
if (input != null) {
312+
LOGGER.debug("Property file {} found on classpath, loading System properties and environment variables", filename);
315313
return loadProperties(input, addProperties);
314+
} else {
315+
LOGGER.debug("Property file not found on classpath, loading System properties and environment variables");
316+
return loadProperties(new Properties(), addProperties);
316317
}
317-
LOGGER.debug("Property file not found on classpath, skipping config file");
318-
return new HashMap<>();
319318
}
320319

321320
/**
@@ -333,21 +332,6 @@ public static Map<Property, Object> loadProperties(final Properties properties,
333332
return unmodifiableMap(RESOLVED_PROPERTIES);
334333
}
335334

336-
/**
337-
* Loads properties from property {@link File}, if provided. Calling this method only has effect on new Email and Mailer instances after this.
338-
*
339-
* @param filename Any file reference that holds a properties list.
340-
* @param addProperties Flag to indicate if the new properties should be added or replacing the old properties.
341-
* @return The updated properties map that is used internally.
342-
*/
343-
public static Map<Property, Object> loadProperties(final File filename, final boolean addProperties) {
344-
try {
345-
return loadProperties(new FileInputStream(filename), addProperties);
346-
} catch (final FileNotFoundException e) {
347-
throw new IllegalStateException("error reading properties file from File", e);
348-
}
349-
}
350-
351335
/**
352336
* Loads properties from {@link InputStream}. Calling this method only has effect on new Email and Mailer instances after this.
353337
*
@@ -380,33 +364,33 @@ public static synchronized Map<Property, Object> loadProperties(final @Nullable
380364
}
381365

382366
/**
383-
* @return All properties in priority of System property {@code >} File properties.
367+
* @return All properties in priority of System property {@code >} Environment variable {@code >} File properties.
384368
*/
385369
private static Map<Property, Object> readProperties(final @NotNull Properties fileProperties) {
386370
final Properties filePropertiesLeft = new Properties();
387371
filePropertiesLeft.putAll(fileProperties);
388372
final Map<Property, Object> resolvedProps = new HashMap<>();
389373
for (final Property prop : Property.values()) {
390-
if (System.getProperty(prop.key) != null) {
391-
LOGGER.debug(prop.key + ": " + System.getProperty(prop.key));
392-
}
393-
final Object asSystemProperty = parsePropertyValue(System.getProperty(prop.key));
394-
if (asSystemProperty != null) {
395-
resolvedProps.put(prop, asSystemProperty);
374+
String systemValue = System.getProperty(prop.key);
375+
String envValue = System.getenv(prop.key.replace('.', '_').toUpperCase());
376+
377+
if (!valueNullOrEmpty(systemValue)) {
378+
LOGGER.debug("{}: {}", prop.key, systemValue);
379+
final Object parsedValue = parsePropertyValue(systemValue);
380+
resolvedProps.put(prop, parsedValue);
381+
filePropertiesLeft.remove(prop.key);
382+
} else if (!valueNullOrEmpty(envValue)) {
383+
LOGGER.debug("{}: {}", prop.key, envValue);
384+
final Object parsedValue = parsePropertyValue(envValue);
385+
resolvedProps.put(prop, parsedValue);
396386
filePropertiesLeft.remove(prop.key);
397387
} else {
398-
final Object asEnvProperty = parsePropertyValue(System.getenv().get(prop.key));
399-
if (asEnvProperty != null) {
400-
resolvedProps.put(prop, asEnvProperty);
401-
filePropertiesLeft.remove(prop.key);
402-
} else {
403-
final Object rawValue = filePropertiesLeft.remove(prop.key);
404-
if (rawValue != null) {
405-
if (rawValue instanceof String) {
406-
resolvedProps.put(prop, parsePropertyValue((String) rawValue));
407-
} else {
408-
resolvedProps.put(prop, rawValue);
409-
}
388+
final Object rawValue = filePropertiesLeft.remove(prop.key);
389+
if (rawValue != null) {
390+
if (rawValue instanceof String) {
391+
resolvedProps.put(prop, parsePropertyValue((String) rawValue));
392+
} else {
393+
resolvedProps.put(prop, rawValue);
410394
}
411395
}
412396
}
@@ -420,7 +404,7 @@ private static Map<Property, Object> readProperties(final @NotNull Properties fi
420404
resolvedProps.put(Property.EXTRA_PROPERTIES, extraProperties);
421405

422406
if (!filePropertiesLeft.isEmpty()) {
423-
throw new IllegalArgumentException("unknown properties provided " + filePropertiesLeft);
407+
throw new IllegalStateException("unknown properties provided " + filePropertiesLeft);
424408
}
425409

426410
return resolvedProps;
@@ -444,7 +428,7 @@ private static Map<String, String> filterExtraJavaMailProperties(@Nullable final
444428
}
445429

446430
/**
447-
* @return The property value in boolean, integer or as original string value.
431+
* @return The property value in boolean, integer, enum, or as the original string value.
448432
*/
449433
@Nullable
450434
static Object parsePropertyValue(final @Nullable String propertyValue) {
@@ -459,40 +443,37 @@ static Object parsePropertyValue(final @Nullable String propertyValue) {
459443
booleanConversionMap.put("true", true);
460444
booleanConversionMap.put("no", false);
461445
booleanConversionMap.put("yes", true);
462-
if (booleanConversionMap.containsKey(propertyValue)) {
446+
if (booleanConversionMap.containsKey(propertyValue.toLowerCase())) {
463447
return booleanConversionMap.get(propertyValue.toLowerCase());
464448
}
465449
// read number value
466450
try {
467451
return Integer.valueOf(propertyValue);
468452
} catch (final NumberFormatException nfe) {
469-
// ok, so not a number
453+
// Not a number
470454
}
471-
// read TransportStrategy value
455+
// read enum values
472456
try {
473457
return TransportStrategy.valueOf(propertyValue);
474458
} catch (final IllegalArgumentException nfe) {
475-
// ok, so not a TransportStrategy either
459+
// Not a TransportStrategy
476460
}
477-
// read ContentTransferEncoding value
478461
try {
479462
return ContentTransferEncoding.valueOf(propertyValue);
480-
} catch (final IllegalArgumentException nfe2) {
481-
// ok, so not a ContentTransferEncoding either
463+
} catch (final IllegalArgumentException nfe) {
464+
// Not a ContentTransferEncoding
482465
}
483-
// read ContentTransferEncoding value
484466
try {
485467
return DkimConfig.Canonicalization.valueOf(propertyValue);
486-
} catch (final IllegalArgumentException nfe2) {
487-
// ok, so not a Canonicalization either
468+
} catch (final IllegalArgumentException nfe) {
469+
// Not a Canonicalization
488470
}
489-
// read LoadBalancingStrategy value
490471
try {
491472
return LoadBalancingStrategy.valueOf(propertyValue);
492473
} catch (final IllegalArgumentException nfe) {
493-
// ok, so not a TransportStrategy either
474+
// Not a LoadBalancingStrategy
494475
}
495-
// return value as is (which should be string)
476+
// return value as is (string)
496477
return propertyValue;
497478
}
498479
}

Diff for: modules/simple-java-mail/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@
9090
<version>1.3.5</version>
9191
<scope>test</scope>
9292
</dependency>
93+
<dependency><!-- used to test loading of Environment properties in ConfigLoaderTest -->
94+
<groupId>org.junit-pioneer</groupId>
95+
<artifactId>junit-pioneer</artifactId>
96+
<version>1.9.1</version>
97+
<scope>test</scope>
98+
</dependency>
9399
</dependencies>
94100

95101
<build>

0 commit comments

Comments
 (0)