ConfigurationUtils.java
package com.bonitasoft.processbuilder.extension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.function.Supplier;
/**
* Utility class for safely retrieving and handling configuration values.
* <p>
* This class provides methods to lookup configuration values with proper logging,
* error handling, and support for sensitive data masking (e.g., passwords).
* </p>
* <p>
* The configuration retrieval is decoupled from the data source through functional interfaces,
* allowing integration with any DAO or configuration provider.
* </p>
*
* <h2>Usage Example:</h2>
* <pre>{@code
* // Example 1: Basic configuration lookup
* String smtpHost = ConfigurationUtils.lookupConfigurationValue(
* SmtpType.SMTP_HOST.getKey(),
* ConfigurationType.SMTP.getKey(),
* () -> pBConfigurationDAO.findByFullNameAndRefEntityTypeName(
* SmtpType.SMTP_HOST.getKey(),
* ConfigurationType.SMTP.getKey()
* ).getConfigValue(),
* "localhost",
* false // not sensitive
* );
*
* // Example 2: Sensitive value lookup (password - value will be masked in logs)
* String password = ConfigurationUtils.lookupConfigurationValue(
* SmtpType.PASSWORD.getKey(),
* ConfigurationType.SMTP.getKey(),
* () -> pBConfigurationDAO.findByFullNameAndRefEntityTypeName(
* SmtpType.PASSWORD.getKey(),
* ConfigurationType.SMTP.getKey()
* ).getConfigValue(),
* "",
* true // sensitive - will be masked in logs
* );
* }</pre>
*
* @author Bonitasoft
* @since 1.0
*/
public final class ConfigurationUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationUtils.class);
/**
* Mask used to hide sensitive values in log output.
*/
public static final String MASKED_VALUE = "********";
/**
* Private constructor to prevent instantiation of this utility class.
*
* @throws UnsupportedOperationException always, to enforce the utility pattern
*/
private ConfigurationUtils() {
throw new UnsupportedOperationException(
"This is a " + this.getClass().getSimpleName() + " class and cannot be instantiated."
);
}
/**
* Looks up a configuration value using a provided supplier, with support for sensitive data masking.
* <p>
* This method encapsulates the common pattern of:
* </p>
* <ol>
* <li>Logging the start of the lookup operation</li>
* <li>Executing the configuration retrieval via the supplier</li>
* <li>Validating the retrieved value</li>
* <li>Returning the value or a default if not found/empty</li>
* <li>Masking sensitive values in log output</li>
* <li>Logging the completion of the operation</li>
* </ol>
*
* @param fullNameKey the configuration key name (e.g., "SmtpHost", "Password")
* @param entityTypeKey the entity type for logging context (e.g., "SMTP", "DATABASE")
* @param configValueSupplier a supplier that retrieves the configuration value;
* may return null if configuration not found
* @param defaultValue the default value to return if configuration is not found or empty
* @param isSensitive if true, the actual value will be masked in log output
* @return the configuration value if found and not empty, otherwise the default value
* @throws RuntimeException if the supplier throws an exception during retrieval
*/
public static String lookupConfigurationValue(
String fullNameKey,
String entityTypeKey,
Supplier<String> configValueSupplier,
String defaultValue,
boolean isSensitive) {
LOGGER.info("--- [ConfigurationUtils] Starting {} configuration lookup ---", fullNameKey);
// Validate inputs
if (fullNameKey == null || fullNameKey.isBlank()) {
LOGGER.warn("fullNameKey is null or blank. Returning default value.");
return defaultValue;
}
if (configValueSupplier == null) {
LOGGER.warn("configValueSupplier is null for {}. Returning default value: {}",
fullNameKey, maskIfSensitive(defaultValue, isSensitive));
return defaultValue;
}
try {
LOGGER.info("Querying configuration with fullName: {} and entityType: {}",
fullNameKey, entityTypeKey);
// Execute the lookup via supplier
String configValue = configValueSupplier.get();
// Validate existence
if (configValue == null || configValue.trim().isEmpty()) {
LOGGER.warn("{} configuration value is null or empty. Returning default value: {}",
fullNameKey, maskIfSensitive(defaultValue, isSensitive));
return defaultValue;
}
// Return the trimmed value
String value = configValue.trim();
LOGGER.info("Successfully retrieved {}: {}",
fullNameKey, maskIfSensitive(value, isSensitive));
return value;
} catch (Exception e) {
LOGGER.error("Unexpected error while querying configuration for {}. Details: {}",
fullNameKey, e.getMessage());
throw new RuntimeException(
"Failed to retrieve " + fullNameKey + " configuration due to an unexpected error.", e);
} finally {
LOGGER.info("--- [ConfigurationUtils] Finished {} configuration lookup ---", fullNameKey);
}
}
/**
* Looks up a configuration value without entity type context.
* <p>
* This is a convenience overload for cases where entity type logging is not needed.
* </p>
*
* @param fullNameKey the configuration key name
* @param configValueSupplier a supplier that retrieves the configuration value
* @param defaultValue the default value to return if configuration is not found
* @param isSensitive if true, the actual value will be masked in log output
* @return the configuration value if found and not empty, otherwise the default value
* @throws RuntimeException if the supplier throws an exception during retrieval
*/
public static String lookupConfigurationValue(
String fullNameKey,
Supplier<String> configValueSupplier,
String defaultValue,
boolean isSensitive) {
return lookupConfigurationValue(fullNameKey, null, configValueSupplier, defaultValue, isSensitive);
}
/**
* Masks a value if it is marked as sensitive.
*
* @param value the value to potentially mask
* @param isSensitive whether the value should be masked
* @return the masked value if sensitive, otherwise the original value
*/
public static String maskIfSensitive(String value, boolean isSensitive) {
if (isSensitive && value != null && !value.isEmpty()) {
return MASKED_VALUE;
}
return value;
}
}