com.ebmwebsourcing.easycommons.properties.PropertiesHelper Maven / Gradle / Ivy
The newest version!
/**
* Copyright (c) 2010-2012 EBM WebSourcing, 2012-2023 Linagora
*
* This program/library is free software: you can redistribute it and/or modify
* it under the terms of the New BSD License (3-clause license).
*
* This program/library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the New BSD License (3-clause license)
* for more details.
*
* You should have received a copy of the New BSD License (3-clause license)
* along with this program/library; If not, see http://directory.fsf.org/wiki/License:BSD_3Clause/
* for the New BSD License (3-clause license).
*/
package com.ebmwebsourcing.easycommons.properties;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.ebmwebsourcing.easycommons.io.IOHelper;
/**
* Utility to handle a CDK properties file.
* @author Adrien Ruffie - EBM WebSourcing
*/
public final class PropertiesHelper {
/**
* Regular expressions for place holder detection
*/
private static final Pattern PLACE_HOLDER_PATTERN = Pattern.compile("\\$\\{([^}]*)\\}");
private static final String PLACE_HOLDER_BEGIN_PATTERN = "\\$\\{";
private static final String PLACE_HOLDER_END_PATTERN = "\\}";
private static final String PLACE_HOLDER_BEGIN = "${";
private static final String PLACE_HOLDER_END = "}";
/**
* Resolve the specified {@link Properties} propertiesToResolve against the
* specified {@link Properties} propertiesToUse. If the place holders of a
* property value cannot be resolved, the place holders are not replaced in
* the resulting resulting value.
*
* @param propertiesToResolve
* the {@link Properties} to resolve (which contain place
* holders)
* @param propertiesToUse
* the {@link Properties} to use to resolve
*
* @throws PropertiesException
* if an error occurs when resolving the {@link Properties} (if
* there is a place holder loop in the specified
* {@link Properties})
*
*/
public static final void resolveProperties(Properties propertiesToResolve,
Properties propertiesToUse) throws PropertiesException {
Set propertyNames = propertiesToResolve.stringPropertyNames();
Properties propertiesToUseToResolve = new Properties();
propertiesToUseToResolve.putAll(propertiesToUse);
propertiesToUseToResolve.putAll(propertiesToResolve);
Properties resolvedProperties = new Properties();
for (String propertyName : propertyNames) {
List parentPropertyNames = new ArrayList();
String propertyValue = resolveProperty(propertiesToUseToResolve, propertyName,
resolvedProperties, parentPropertyNames);
propertiesToResolve.put(propertyName, propertyValue);
}
}
/**
* Resolve the place holders in the values of the specified
* {@link InputStream} inputStreamToResolve against the specified
* {@link Properties} propertiesToUse. If the place holders of a property
* value cannot be resolved, the place holders are not replaced in the
* resulting resulting value.
*
* @param inputStreamToResolve
* the {@link InputStream} containing properties value with place
* holders to resolve
* @param propertiesToUse
* the {@link Properties} to use to resolve
*
* @throws PropertiesException
* if an error occurs when resolving the {@link Properties} (if
* there is a place holder loop in the specified
* {@link Properties})
* @throws IOException
* if an error occurred when reading from the specified input
* stream or if writing this resolved property list to the
* specified output stream throws an IOException.
*/
public static final ByteArrayInputStream resolvePropertiesForInputStream(
InputStream inputStreamToResolve, Properties propertiesToUse)
throws PropertiesException, IOException {
assert inputStreamToResolve != null;
ByteArrayInputStream resultInputStream = null;
ByteArrayOutputStream out = null;
try {
Properties propertiesToResolve = new Properties();
propertiesToResolve.load(inputStreamToResolve);
resolveProperties(propertiesToResolve, propertiesToUse);
out = new ByteArrayOutputStream();
propertiesToResolve.store(out, "");
resultInputStream = new ByteArrayInputStream(out.toByteArray());
} finally {
IOHelper.close(out);
}
return resultInputStream;
}
/**
* Resolve the place holders in the values of the specified {@link Map}
* mapToResolve against the specified {@link Properties} propertiesToUse. If
* the resolution of place holders fails, the string value is not modified
* in the map.
*
* @param mapToResolve
* the {@link Map} containing string value with place holders to
* resolve
* @param propertiesToUse
* the {@link Properties} to use to resolve
*
*/
public static final void resolveMapWithNoException(Map mapToResolve,
Properties propertiesToUse) {
Properties resolvedProperties = new Properties();
for (Entry e : mapToResolve.entrySet()) {
try {
String newValue = resolveString(e.getValue(), propertiesToUse, resolvedProperties);
e.setValue(newValue);
} catch (PropertiesException pe) {
// let the value with the place holders in case of error
}
}
}
/**
* Resolve the place holders in the values of the specified {@link Map}
* mapToResolve against the specified {@link Properties} propertiesToUse. If
* the place holders of a string value cannot be resolved, the place holders
* are not replaced in the resulting string (only the resolved place holders
* are replaced, not the others).
*
* @param mapToResolve
* the {@link Map} containing string value with place holders to
* resolve
* @param propertiesToUse
* the {@link Properties} to use to resolve
*
* @throws PropertiesException
* if an error occurs when resolving the {@link Properties} (if
* there is a place holder loop in the specified
* {@link Properties})
*/
public static final void resolveMap(Map mapToResolve, Properties propertiesToUse)
throws PropertiesException {
Properties resolvedProperties = new Properties();
for (Entry e : mapToResolve.entrySet()) {
String newValue = resolveString(e.getValue(), propertiesToUse, resolvedProperties);
e.setValue(newValue);
}
}
/**
* Replace the place holders by their values in the specified string str. If
* place holders of the string str cannot be resolved, they are not replaced
* in the resulting string.
*
* @param str
* a string containing place holders
* @param propertiesToUse
* the {@link Properties} to resolve (which contains place
* holders)
*
* @return the string where the place holders have been replaced by their
* values (the places holders which cannot be resolved are still
* present in the resulting string)
*
* @throws PropertiesException
* if an error occurs when resolving a place holder (if there is
* a place holder loop in the specified {@link Properties})
*/
public static final String resolveString(String str, Properties propertiesToUse)
throws PropertiesException {
Properties resolvedProperties = new Properties();
return resolveString(str, propertiesToUse, resolvedProperties);
}
/**
* Test if the specified string contains at least one place holder
*
* @param str
* a string
*
* @return true if the specified string contains at least one place holder
*/
public static final boolean containsPlaceHolder(String str) {
Matcher matcher = PLACE_HOLDER_PATTERN.matcher(str);
return matcher.find();
}
private static final String resolveString(String str, Properties propertiesToUse,
Properties resolvedProperties) throws PropertiesException {
Matcher matcher = PLACE_HOLDER_PATTERN.matcher(str);
while (matcher.find()) {
String propertyName = matcher.group(1);
List parentPropertyNames = new ArrayList();
String propertyValue = resolveProperty(propertiesToUse, propertyName,
resolvedProperties, parentPropertyNames);
str = str.replaceAll(PLACE_HOLDER_BEGIN_PATTERN + propertyName
+ PLACE_HOLDER_END_PATTERN, Matcher.quoteReplacement(propertyValue));
}
return str;
}
private static final String resolveProperty(Properties propertiesToUse, String propertyName,
Properties resolvedProperties, List parentPropertyNames)
throws PropertiesException {
String propertyValue;
if (resolvedProperties.containsKey(propertyName)) {
propertyValue = resolvedProperties.getProperty(propertyName);
} else {
propertyValue = propertiesToUse.getProperty(propertyName);
if (propertyValue != null) {
Matcher matcher = PLACE_HOLDER_PATTERN.matcher(propertyValue);
if (matcher.find()) {
List alreadyReplacedProperties = new ArrayList();
do {
String subPropertyName = matcher.group(1);
if (parentPropertyNames.contains(subPropertyName)) {
throw new PropertiesException(
"There is a place holder loop in the specified properties");
} else if (!alreadyReplacedProperties.contains(subPropertyName)) {
parentPropertyNames.add(subPropertyName);
String subPropertyValue = resolveProperty(propertiesToUse,
subPropertyName, resolvedProperties, parentPropertyNames);
parentPropertyNames.remove(subPropertyName);
propertyValue = propertyValue.replaceAll(PLACE_HOLDER_BEGIN_PATTERN
+ subPropertyName + PLACE_HOLDER_END_PATTERN,
Matcher.quoteReplacement(subPropertyValue));
alreadyReplacedProperties.add(subPropertyName);
}
} while (matcher.find());
resolvedProperties.put(propertyName, propertyValue);
}
} else {
propertyValue = PLACE_HOLDER_BEGIN + propertyName + PLACE_HOLDER_END;
resolvedProperties.put(propertyName, propertyValue);
}
}
return propertyValue;
}
/**
* Get a flat view of a {@link Properties} object including recursively,
* default properties if any.
*
* @param properties
* Properties to consider.
* @return Flatten properties.
*/
public static final Properties flattenProperties(Properties properties) {
assert properties != null;
Properties flattenProperties = new Properties();
for (Object propertyName : Collections.list(properties.propertyNames())) {
assert propertyName instanceof String;
flattenProperties.put((String) propertyName,
properties.getProperty((String) propertyName));
}
return flattenProperties;
}
/**
* Parse the values of a property. Delimiter are whitespace or comma
* character.
*
* @param propValue
* @return an array of string containing the extracted values.
*
*/
public static String[] parsePropertyValues(String propValue) {
assert propValue != null;
propValue = propValue.trim();
int idx = 0;
List result = new ArrayList();
while (idx < propValue.length()) {
int end = idx;
while (end < propValue.length()) {
if (Character.isWhitespace(propValue.charAt(end))) {
break;
}
if (propValue.charAt(end) == ',') {
break;
}
end++;
}
String word = propValue.substring(idx, end);
idx = end + 1;
word = word.trim();
if (word.length() == 0) {
continue;
}
result.add(word);
}
return result.toArray(new String[result.size()]);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy