1010import org .slf4j .Logger ;
1111import org .slf4j .LoggerFactory ;
1212
13- import java .io .File ;
14- import java .io .FileInputStream ;
15- import java .io .FileNotFoundException ;
1613import java .io .IOException ;
1714import java .io .InputStream ;
1815import java .util .HashMap ;
106103public 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}
0 commit comments