All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.simplejavamail.config.ConfigLoader Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 2009 Benny Bottema ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.simplejavamail.config;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.simplejavamail.api.email.ContentTransferEncoding;
import org.simplejavamail.api.email.config.DkimConfig;
import org.simplejavamail.api.mailer.config.LoadBalancingStrategy;
import org.simplejavamail.api.mailer.config.TransportStrategy;
import org.simplejavamail.internal.util.SimpleConversions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.Collections.unmodifiableMap;
import static java.util.regex.Pattern.compile;
import static org.simplejavamail.internal.util.MiscUtil.checkArgumentNotEmpty;
import static org.simplejavamail.internal.util.MiscUtil.valueNullOrEmpty;
import static org.simplejavamail.internal.util.Preconditions.assumeTrue;

/**
 * Contains list of possible properties names and can produce a map of property values, if provided as file {@value #DEFAULT_CONFIG_FILENAME} on the
 * classpath or as environment property.
 * 

* The following properties are allowed: *

    *
  • simplejavamail.javaxmail.debug
  • *
  • simplejavamail.transportstrategy
  • *
  • simplejavamail.smtp.host
  • *
  • simplejavamail.smtp.port
  • *
  • simplejavamail.smtp.username
  • *
  • simplejavamail.smtp.password
  • *
  • simplejavamail.disable.all.clientvalidation
  • *
  • simplejavamail.custom.sslfactory.class
  • *
  • simplejavamail.proxy.host
  • *
  • simplejavamail.proxy.port
  • *
  • simplejavamail.proxy.username
  • *
  • simplejavamail.proxy.password
  • *
  • simplejavamail.proxy.socks5bridge.port
  • *
  • simplejavamail.defaults.content.transfer.encoding
  • *
  • simplejavamail.defaults.subject
  • *
  • simplejavamail.defaults.from.name
  • *
  • simplejavamail.defaults.from.address
  • *
  • simplejavamail.defaults.replyto.name
  • *
  • simplejavamail.defaults.replyto.address
  • *
  • simplejavamail.defaults.bounceto.name
  • *
  • simplejavamail.defaults.bounceto.address
  • *
  • simplejavamail.defaults.to.name
  • *
  • simplejavamail.defaults.to.address
  • *
  • simplejavamail.defaults.cc.name
  • *
  • simplejavamail.defaults.cc.address
  • *
  • simplejavamail.defaults.bcc.name
  • *
  • simplejavamail.defaults.bcc.address
  • *
  • simplejavamail.defaults.poolsize
  • *
  • simplejavamail.defaults.poolsize.keepalivetime
  • *
  • simplejavamail.defaults.connectionpool.clusterkey.uuid
  • *
  • simplejavamail.defaults.connectionpool.coresize
  • *
  • simplejavamail.defaults.connectionpool.maxsize
  • *
  • simplejavamail.defaults.connectionpool.claimtimeout.millis
  • *
  • simplejavamail.defaults.connectionpool.expireafter.millis
  • *
  • simplejavamail.defaults.connectionpool.loadbalancing.strategy
  • *
  • simplejavamail.defaults.sessiontimeoutmillis
  • *
  • simplejavamail.defaults.trustallhosts
  • *
  • simplejavamail.defaults.trustedhosts
  • *
  • simplejavamail.defaults.verifyserveridentity
  • *
  • simplejavamail.transport.mode.logging.only
  • *
  • simplejavamail.opportunistic.tls
  • *
  • simplejavamail.smime.signing.keystore
  • *
  • simplejavamail.smime.signing.keystore_password
  • *
  • simplejavamail.smime.signing.key_alias
  • *
  • simplejavamail.smime.signing.key_password
  • *
  • simplejavamail.smime.encryption.certificate
  • *
  • simplejavamail.smime.signing.algorithm
  • *
  • simplejavamail.smime.encryption.key_encapsulation_algorithm
  • *
  • simplejavamail.smime.encryption.cipher
  • *
  • simplejavamail.dkim.signing.private_key_file_or_data
  • *
  • simplejavamail.dkim.signing.selector
  • *
  • simplejavamail.dkim.signing.signing_domain
  • *
  • simplejavamail.dkim.signing.use_length_param
  • *
  • simplejavamail.dkim.signing.excluded_headers_from_default_signing_list
  • *
  • simplejavamail.dkim.signing.header_canonicalization
  • *
  • simplejavamail.dkim.signing.body_canonicalization
  • *
  • simplejavamail.dkim.signing.algorithm
  • *
  • simplejavamail.embeddedimages.dynamicresolution.enable.dir
  • *
  • simplejavamail.embeddedimages.dynamicresolution.enable.url
  • *
  • simplejavamail.embeddedimages.dynamicresolution.enable.classpath
  • *
  • simplejavamail.embeddedimages.dynamicresolution.base.dir
  • *
  • simplejavamail.embeddedimages.dynamicresolution.base.url
  • *
  • simplejavamail.embeddedimages.dynamicresolution.base.classpath
  • *
  • simplejavamail.embeddedimages.dynamicresolution.outside.base.dir
  • *
  • simplejavamail.embeddedimages.dynamicresolution.outside.base.classpath
  • *
  • simplejavamail.embeddedimages.dynamicresolution.outside.base.url
  • *
  • simplejavamail.embeddedimages.dynamicresolution.mustbesuccesful
  • *
*/ public final class ConfigLoader { private static final Logger LOGGER = LoggerFactory.getLogger(ConfigLoader.class); /** * By default, the optional file {@value} will be loaded from classpath to load initial defaults. */ public static final String DEFAULT_CONFIG_FILENAME = "simplejavamail.properties"; /** * This pattern recognizes extra property lines that should be loaded directly into JavaMail on the Session object. */ private static final Pattern EXTRA_PROPERTY_PATTERN = compile("^simplejavamail\\.extraproperties\\.(?.*)"); /** * Initially try to load properties from "{@value #DEFAULT_CONFIG_FILENAME}". * * @see #loadProperties(String, boolean) * @see #loadProperties(InputStream, boolean) */ private static final Map RESOLVED_PROPERTIES = new HashMap<>(); static { // static initializer block, because loadProperties needs to modify RESOLVED_PROPERTIES while loading // this is not possible when we are initializing the same field. // RESOLVED_PROPERTIES = loadProperties(DEFAULT_CONFIG_FILENAME); <-- not possible loadProperties(DEFAULT_CONFIG_FILENAME, false); } /** * List of all the properties recognized by Simple Java Mail. Can be used to programmatically get, set or remove default values. * * @see simplejavamail.org */ public enum Property { JAVAXMAIL_DEBUG("simplejavamail.javaxmail.debug"), TRANSPORT_STRATEGY("simplejavamail.transportstrategy"), SMTP_HOST("simplejavamail.smtp.host"), SMTP_PORT("simplejavamail.smtp.port"), SMTP_USERNAME("simplejavamail.smtp.username"), SMTP_PASSWORD("simplejavamail.smtp.password"), DISABLE_ALL_CLIENTVALIDATION("simplejavamail.disable.all.clientvalidation"), CUSTOM_SSLFACTORY_CLASS("simplejavamail.custom.sslfactory.class"), PROXY_HOST("simplejavamail.proxy.host"), PROXY_PORT("simplejavamail.proxy.port"), PROXY_USERNAME("simplejavamail.proxy.username"), PROXY_PASSWORD("simplejavamail.proxy.password"), PROXY_SOCKS5BRIDGE_PORT("simplejavamail.proxy.socks5bridge.port"), DEFAULT_SUBJECT("simplejavamail.defaults.subject"), DEFAULT_CONTENT_TRANSFER_ENCODING("simplejavamail.defaults.content.transfer.encoding"), DEFAULT_FROM_NAME("simplejavamail.defaults.from.name"), DEFAULT_FROM_ADDRESS("simplejavamail.defaults.from.address"), DEFAULT_REPLYTO_NAME("simplejavamail.defaults.replyto.name"), DEFAULT_REPLYTO_ADDRESS("simplejavamail.defaults.replyto.address"), DEFAULT_BOUNCETO_NAME("simplejavamail.defaults.bounceto.name"), DEFAULT_BOUNCETO_ADDRESS("simplejavamail.defaults.bounceto.address"), DEFAULT_TO_NAME("simplejavamail.defaults.to.name"), DEFAULT_TO_ADDRESS("simplejavamail.defaults.to.address"), DEFAULT_CC_NAME("simplejavamail.defaults.cc.name"), DEFAULT_CC_ADDRESS("simplejavamail.defaults.cc.address"), DEFAULT_BCC_NAME("simplejavamail.defaults.bcc.name"), DEFAULT_BCC_ADDRESS("simplejavamail.defaults.bcc.address"), DEFAULT_POOL_SIZE("simplejavamail.defaults.poolsize"), DEFAULT_CONNECTIONPOOL_CLUSTER_KEY("simplejavamail.defaults.connectionpool.clusterkey.uuid"), DEFAULT_CONNECTIONPOOL_CORE_SIZE("simplejavamail.defaults.connectionpool.coresize"), DEFAULT_CONNECTIONPOOL_MAX_SIZE("simplejavamail.defaults.connectionpool.maxsize"), DEFAULT_CONNECTIONPOOL_CLAIMTIMEOUT_MILLIS("simplejavamail.defaults.connectionpool.claimtimeout.millis"), DEFAULT_CONNECTIONPOOL_EXPIREAFTER_MILLIS("simplejavamail.defaults.connectionpool.expireafter.millis"), DEFAULT_CONNECTIONPOOL_LOADBALANCING_STRATEGY("simplejavamail.defaults.connectionpool.loadbalancing.strategy"), DEFAULT_POOL_KEEP_ALIVE_TIME("simplejavamail.defaults.poolsize.keepalivetime"), DEFAULT_SESSION_TIMEOUT_MILLIS("simplejavamail.defaults.sessiontimeoutmillis"), DEFAULT_TRUST_ALL_HOSTS("simplejavamail.defaults.trustallhosts"), DEFAULT_TRUSTED_HOSTS("simplejavamail.defaults.trustedhosts"), DEFAULT_VERIFY_SERVER_IDENTITY("simplejavamail.defaults.verifyserveridentity"), TRANSPORT_MODE_LOGGING_ONLY("simplejavamail.transport.mode.logging.only"), OPPORTUNISTIC_TLS("simplejavamail.opportunistic.tls"), SMIME_SIGNING_KEYSTORE("simplejavamail.smime.signing.keystore"), SMIME_SIGNING_KEYSTORE_PASSWORD("simplejavamail.smime.signing.keystore_password"), SMIME_SIGNING_KEY_ALIAS("simplejavamail.smime.signing.key_alias"), SMIME_SIGNING_KEY_PASSWORD("simplejavamail.smime.signing.key_password"), SMIME_SIGNING_ALGORITHM("simplejavamail.smime.signing.algorithm"), SMIME_ENCRYPTION_KEY_ENCAPSULATION_ALGORITHM("simplejavamail.smime.encryption.key_encapsulation_algorithm"), SMIME_ENCRYPTION_CIPHER("simplejavamail.smime.encryption.cipher"), DKIM_PRIVATE_KEY_FILE_OR_DATA("simplejavamail.dkim.signing.private_key_file_or_data"), DKIM_SELECTOR("simplejavamail.dkim.signing.selector"), DKIM_SIGNING_DOMAIN("simplejavamail.dkim.signing.signing_domain"), DKIM_SIGNING_USE_LENGTH_PARAM("simplejavamail.dkim.signing.use_length_param"), DKIM_EXCLUDED_HEADERS_FROM_DEFAULT_SIGNING_LIST("simplejavamail.dkim.signing.excluded_headers_from_default_signing_list"), DKIM_SIGNING_HEADER_CANONICALIZATION("simplejavamail.dkim.signing.header_canonicalization"), DKIM_SIGNING_BODY_CANONICALIZATION("simplejavamail.dkim.signing.body_canonicalization"), DKIM_SIGNING_ALGORITHM("simplejavamail.dkim.signing.algorithm"), SMIME_ENCRYPTION_CERTIFICATE("simplejavamail.smime.encryption.certificate"), EMBEDDEDIMAGES_DYNAMICRESOLUTION_ENABLE_DIR("simplejavamail.embeddedimages.dynamicresolution.enable.dir"), EMBEDDEDIMAGES_DYNAMICRESOLUTION_ENABLE_CLASSPATH("simplejavamail.embeddedimages.dynamicresolution.enable.classpath"), EMBEDDEDIMAGES_DYNAMICRESOLUTION_ENABLE_URL("simplejavamail.embeddedimages.dynamicresolution.enable.url"), EMBEDDEDIMAGES_DYNAMICRESOLUTION_BASE_DIR("simplejavamail.embeddedimages.dynamicresolution.base.dir"), EMBEDDEDIMAGES_DYNAMICRESOLUTION_BASE_CLASSPATH("simplejavamail.embeddedimages.dynamicresolution.base.classpath"), EMBEDDEDIMAGES_DYNAMICRESOLUTION_BASE_URL("simplejavamail.embeddedimages.dynamicresolution.base.url"), EMBEDDEDIMAGES_DYNAMICRESOLUTION_OUTSIDE_BASE_DIR("simplejavamail.embeddedimages.dynamicresolution.outside.base.dir"), EMBEDDEDIMAGES_DYNAMICRESOLUTION_OUTSIDE_BASE_URL("simplejavamail.embeddedimages.dynamicresolution.outside.base.classpath"), EMBEDDEDIMAGES_DYNAMICRESOLUTION_OUTSIDE_BASE_CLASSPATH("simplejavamail.embeddedimages.dynamicresolution.outside.base.url"), EMBEDDEDIMAGES_DYNAMICRESOLUTION_MUSTBESUCCESFUL("simplejavamail.embeddedimages.dynamicresolution.mustbesuccesful"), EXTRA_PROPERTIES("simplejavamail.extraproperties.*"); private final String key; Property(final String key) { this.key = key; } public String key() { return key; } } private ConfigLoader() { } /** * @return The value if not null or else the value from config file if provided or else null. */ @Nullable public static T valueOrProperty(final @Nullable T value, final Property property) { return valueOrProperty(value, property, null); } /** * See {@link #valueOrProperty(Object, Property, Object)}. */ @Nullable public static String valueOrPropertyAsString(@Nullable final String value, @NotNull final Property property, @Nullable final String defaultValue) { return SimpleConversions.convertToString(valueOrProperty(value, property, defaultValue)); } /** * See {@link #valueOrProperty(Object, Property, Object)}. */ @Nullable public static Boolean valueOrPropertyAsBoolean(@Nullable final Boolean value, @NotNull final Property property, @Nullable final Boolean defaultValue) { return SimpleConversions.convertToBoolean(valueOrProperty(value, property, defaultValue)); } /** * See {@link #valueOrProperty(Object, Property, Object)}. */ @Nullable public static Integer valueOrPropertyAsInteger(@Nullable final Integer value, @NotNull final Property property, @Nullable final Integer defaultValue) { return SimpleConversions.convertToInteger(valueOrProperty(value, property, defaultValue)); } /** * 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 * provided. *

* Null or blank values are never allowed, so they are always ignored. * * @return The value if not null or else the value from config file if provided or else defaultValue. */ @Nullable public static T valueOrProperty(@Nullable final T value, @NotNull final Property property, @Nullable final T defaultValue) { if (!valueNullOrEmpty(value)) { LOGGER.trace("using provided argument value {} for property {}", value, property); return value; } else if (hasProperty(property)) { final T propertyValue = getProperty(property); LOGGER.trace("using value {} from config file for property {}", propertyValue, property); return propertyValue; } else { LOGGER.trace("no value provided as argument or in config file for property {}, using default value {}", property, defaultValue); return defaultValue; } } public static synchronized boolean hasProperty(final Property property) { return !valueNullOrEmpty(RESOLVED_PROPERTIES.get(property)); } @SuppressWarnings("unchecked") @Nullable public static synchronized T getProperty(final Property property) { return (T) RESOLVED_PROPERTIES.get(property); } @Nullable public static synchronized String getStringProperty(final Property property) { return SimpleConversions.convertToString(RESOLVED_PROPERTIES.get(property)); } @Nullable public static synchronized Integer getIntegerProperty(final Property property) { return SimpleConversions.convertToInteger(RESOLVED_PROPERTIES.get(property)); } @Nullable public static synchronized Boolean getBooleanProperty(final Property property) { return SimpleConversions.convertToBoolean(RESOLVED_PROPERTIES.get(property)); } /** * Loads properties from property file on the classpath, if provided. Calling this method only has effect on new Email and Mailer instances after * this. * * @param filename Any file that is on the classpath that holds a list of key=value pairs. * @param addProperties Flag to indicate if the new properties should be added or replacing the old properties. * @return The updated properties map that is used internally. */ public static Map loadProperties(final String filename, final boolean addProperties) { final InputStream input = ConfigLoader.class.getClassLoader().getResourceAsStream(filename); if (input != null) { LOGGER.debug("Property file {} found on classpath, loading System properties and environment variables", filename); return loadProperties(input, addProperties); } else { LOGGER.debug("Property file not found on classpath, loading System properties and environment variables"); return loadProperties(new Properties(), addProperties); } } /** * Loads properties from another properties source, in case you want to provide your own list. * * @param properties Your own list of properties * @param addProperties Flag to indicate if the new properties should be added or replacing the old properties. * @return The updated properties map that is used internally. */ public static Map loadProperties(final Properties properties, final boolean addProperties) { if (!addProperties) { RESOLVED_PROPERTIES.clear(); } RESOLVED_PROPERTIES.putAll(readProperties(properties)); return unmodifiableMap(RESOLVED_PROPERTIES); } /** * Loads properties from {@link InputStream}. Calling this method only has effect on new Email and Mailer instances after this. * * @param inputStream Source of property key=value pairs separated by newline \n characters. * @param addProperties Flag to indicate if the new properties should be added or replacing the old properties. * @return The updated properties map that is used internally. */ public static synchronized Map loadProperties(final @Nullable InputStream inputStream, final boolean addProperties) { final Properties prop = new Properties(); try { prop.load(checkArgumentNotEmpty(inputStream, "InputStream was null")); } catch (final IOException e) { throw new IllegalStateException("error reading properties file from inputstream", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (final IOException e) { LOGGER.error(e.getMessage(), e); } } } if (!addProperties) { RESOLVED_PROPERTIES.clear(); } RESOLVED_PROPERTIES.putAll(readProperties(prop)); return unmodifiableMap(RESOLVED_PROPERTIES); } /** * @return All properties in priority of System property {@code >} Environment variable {@code >} File properties. */ private static Map readProperties(final @NotNull Properties fileProperties) { final Properties filePropertiesLeft = new Properties(); filePropertiesLeft.putAll(fileProperties); final Map resolvedProps = new HashMap<>(); for (final Property prop : Property.values()) { String systemValue = System.getProperty(prop.key); String envValue = System.getenv(prop.key.replace('.', '_').toUpperCase()); if (!valueNullOrEmpty(systemValue)) { LOGGER.debug("{}: {}", prop.key, systemValue); final Object parsedValue = parsePropertyValue(systemValue); resolvedProps.put(prop, parsedValue); filePropertiesLeft.remove(prop.key); } else if (!valueNullOrEmpty(envValue)) { LOGGER.debug("{}: {}", prop.key, envValue); final Object parsedValue = parsePropertyValue(envValue); resolvedProps.put(prop, parsedValue); filePropertiesLeft.remove(prop.key); } else { final Object rawValue = filePropertiesLeft.remove(prop.key); if (rawValue != null) { if (rawValue instanceof String) { resolvedProps.put(prop, parsePropertyValue((String) rawValue)); } else { resolvedProps.put(prop, rawValue); } } } } final Map extraProperties = new HashMap<>(); extraProperties.putAll(filterExtraJavaMailProperties(null, System.getProperties().entrySet())); //noinspection unchecked,rawtypes extraProperties.putAll(filterExtraJavaMailProperties(null, (Set) System.getenv().entrySet())); extraProperties.putAll(filterExtraJavaMailProperties(filePropertiesLeft, fileProperties.entrySet())); resolvedProps.put(Property.EXTRA_PROPERTIES, extraProperties); if (!filePropertiesLeft.isEmpty()) { throw new IllegalStateException("unknown properties provided " + filePropertiesLeft); } return resolvedProps; } private static Map filterExtraJavaMailProperties(@Nullable final Properties filePropertiesLeft, final Set> entries) { final Map extraProperties = new HashMap<>(); for (Map.Entry propertyKey : entries) { if (propertyKey.getKey() instanceof String) { final Matcher matcher = EXTRA_PROPERTY_PATTERN.matcher((String) propertyKey.getKey()); if (matcher.matches()) { assumeTrue(propertyKey.getValue() instanceof String, "Simple Java Mail property value can only be of type String"); extraProperties.put(matcher.group("actualProperty"), (String) propertyKey.getValue()); if (filePropertiesLeft != null) { filePropertiesLeft.remove(propertyKey.getKey()); } } } } return extraProperties; } /** * @return The property value in boolean, integer, enum, or as the original string value. */ @Nullable static Object parsePropertyValue(final @Nullable String propertyValue) { if (propertyValue == null) { return null; } // read boolean value final Map booleanConversionMap = new HashMap<>(); booleanConversionMap.put("0", false); booleanConversionMap.put("1", true); booleanConversionMap.put("false", false); booleanConversionMap.put("true", true); booleanConversionMap.put("no", false); booleanConversionMap.put("yes", true); if (booleanConversionMap.containsKey(propertyValue.toLowerCase())) { return booleanConversionMap.get(propertyValue.toLowerCase()); } // read number value try { return Integer.valueOf(propertyValue); } catch (final NumberFormatException nfe) { // Not a number } // read enum values try { return TransportStrategy.valueOf(propertyValue); } catch (final IllegalArgumentException nfe) { // Not a TransportStrategy } try { return ContentTransferEncoding.valueOf(propertyValue); } catch (final IllegalArgumentException nfe) { // Not a ContentTransferEncoding } try { return DkimConfig.Canonicalization.valueOf(propertyValue); } catch (final IllegalArgumentException nfe) { // Not a Canonicalization } try { return LoadBalancingStrategy.valueOf(propertyValue); } catch (final IllegalArgumentException nfe) { // Not a LoadBalancingStrategy } // return value as is (string) return propertyValue; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy