Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright 2010-2012 The Kuali Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
*
* 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.kuali.common.util;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.kuali.common.util.property.Constants;
import org.kuali.common.util.property.GlobalPropertiesMode;
import org.kuali.common.util.property.processor.AddPropertiesProcessor;
import org.kuali.common.util.property.processor.PropertyProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.PropertyPlaceholderHelper;
/**
* Simplify handling of Properties especially as it relates to storing and loading. Properties can be loaded from
* any url Spring resource loading can understand. When storing and loading, locations ending in .xml are automatically handled
* using storeToXML() and loadFromXML(), respectively. Properties are always stored in sorted order
* with the encoding indicated via a comment.
*/
public class PropertyUtils {
private static final Logger logger = LoggerFactory.getLogger(PropertyUtils.class);
private static final String XML_EXTENSION = ".xml";
private static final String ENV_PREFIX = "env";
private static final String DEFAULT_ENCODING = Charset.defaultCharset().name();
private static final String DEFAULT_XML_ENCODING = "UTF-8";
public static final Properties combine(List properties) {
Properties combined = new Properties();
for (Properties p : properties) {
combined.putAll(PropertyUtils.toEmpty(p));
}
return combined;
}
public static final Properties combine(Properties... properties) {
return combine(Arrays.asList(properties));
}
public static final void process(Properties properties, PropertyProcessor processor) {
process(properties, Collections.singletonList(processor));
}
public static final void process(Properties properties, List processors) {
for (PropertyProcessor processor : processors) {
processor.process(properties);
}
}
public static final Properties toEmpty(Properties properties) {
return properties == null ? new Properties() : properties;
}
public static final boolean isSingleUnresolvedPlaceholder(String string) {
return isSingleUnresolvedPlaceholder(string, Constants.DEFAULT_PLACEHOLDER_PREFIX, Constants.DEFAULT_PLACEHOLDER_SUFFIX);
}
public static final boolean isSingleUnresolvedPlaceholder(String string, String prefix, String suffix) {
int prefixMatches = StringUtils.countMatches(string, prefix);
int suffixMatches = StringUtils.countMatches(string, suffix);
boolean startsWith = StringUtils.startsWith(string, prefix);
boolean endsWith = StringUtils.endsWith(string, suffix);
return prefixMatches == 1 && suffixMatches == 1 && startsWith && endsWith;
}
public static final boolean containsUnresolvedPlaceholder2(String string) {
int beginIndex = StringUtils.indexOf(string, Constants.DEFAULT_PLACEHOLDER_PREFIX);
if (beginIndex == -1) {
return false;
}
int endIndex = StringUtils.indexOf(string, Constants.DEFAULT_PLACEHOLDER_SUFFIX, beginIndex);
if (endIndex == -1) {
return false;
}
String substring = StringUtils.substring(string, beginIndex, endIndex);
return StringUtils.indexOf(substring, Constants.DEFAULT_VALUE_SEPARATOR) == -1;
}
public static final boolean containsUnresolvedPlaceholder(String string) {
return containsUnresolvedPlaceholder(string, Constants.DEFAULT_PLACEHOLDER_PREFIX, Constants.DEFAULT_PLACEHOLDER_SUFFIX);
}
public static final boolean containsUnresolvedPlaceholder(String string, String prefix, String suffix) {
int beginIndex = StringUtils.indexOf(string, prefix);
if (beginIndex == -1) {
return false;
}
return StringUtils.indexOf(string, suffix) != -1;
}
/**
* Return a new Properties object containing only those properties where the resolved value is different from the original
* value. Using global properties to perform property resolution as indicated by Constants.DEFAULT_GLOBAL_PROPERTIES_MODE
*/
public static final Properties getResolvedProperties(Properties properties) {
return getResolvedProperties(properties, Constants.DEFAULT_PROPERTY_PLACEHOLDER_HELPER, Constants.DEFAULT_GLOBAL_PROPERTIES_MODE);
}
/**
* Return a new Properties object containing only those properties where the resolved value is different from the original
* value. Using global properties to perform property resolution as indicated by globalPropertiesMode
*/
public static final Properties getResolvedProperties(Properties properties, GlobalPropertiesMode globalPropertiesMode) {
return getResolvedProperties(properties, Constants.DEFAULT_PROPERTY_PLACEHOLDER_HELPER, globalPropertiesMode);
}
/**
* Return a new Properties object containing only those properties where the resolved value is different from the original
* value. Using global properties to perform property resolution as indicated by Constants.DEFAULT_GLOBAL_PROPERTIES_MODE
*/
public static final Properties getResolvedProperties(Properties properties, PropertyPlaceholderHelper helper) {
return getResolvedProperties(properties, helper, Constants.DEFAULT_GLOBAL_PROPERTIES_MODE);
}
/**
* Return a new Properties object containing only those properties where the resolved value is different from the original
* value. Using global properties to perform property resolution as indicated by globalPropertiesMode
*/
public static final Properties getResolvedProperties(Properties properties, PropertyPlaceholderHelper helper, GlobalPropertiesMode globalPropertiesMode) {
Properties global = PropertyUtils.getProperties(properties, globalPropertiesMode);
List keys = PropertyUtils.getSortedKeys(properties);
Properties newProperties = new Properties();
for (String key : keys) {
String originalValue = properties.getProperty(key);
String resolvedValue = helper.replacePlaceholders(originalValue, global);
if (!resolvedValue.equals(originalValue)) {
logger.debug("Resolved property '" + key + "' [{}] -> [{}]", Str.flatten(originalValue), Str.flatten(resolvedValue));
newProperties.setProperty(key, resolvedValue);
}
}
return newProperties;
}
/**
* Return the property values from keys
*/
public static final List getValues(Properties properties, List keys) {
List values = new ArrayList();
for (String key : keys) {
values.add(properties.getProperty(key));
}
return values;
}
/**
* Return a sorted List of keys from properties that end with suffix.
*/
public static final List getEndsWithKeys(Properties properties, String suffix) {
List keys = getSortedKeys(properties);
List matches = new ArrayList();
for (String key : keys) {
if (StringUtils.endsWith(key, suffix)) {
matches.add(key);
}
}
return matches;
}
/**
* Alter the properties passed in to contain only the desired property values. includes and
* excludes are comma separated values.
*/
public static final void trim(Properties properties, String includesCSV, String excludesCSV) {
List includes = CollectionUtils.getTrimmedListFromCSV(includesCSV);
List excludes = CollectionUtils.getTrimmedListFromCSV(excludesCSV);
trim(properties, includes, excludes);
}
/**
* Alter the properties passed in to contain only the desired property values.
*/
public static final void trim(Properties properties, List includes, List excludes) {
List keys = getSortedKeys(properties);
for (String key : keys) {
if (!include(key, includes, excludes)) {
logger.debug("Removing [{}]", key);
properties.remove(key);
}
}
}
/**
* Return true if value should be included, false otherwise.
* If excludes is not empty and matches value return false.
* If value has not been explicitly excluded, check the includes list.
* If includes is empty return true.
* If includes is not empty, return true if, and only if, value matches a pattern from the
* includes list.
* A single wildcard * pattern is supported for includes and excludes.
* If value contains the wildcard symbol *, IllegalArgumentException is thrown if the
* include/exclude lists also contain strings with the wildcard symbol *
*/
public static final boolean include(String value, List includes, List excludes) {
if (singleWildcardMatch(value, excludes)) {
// No point incurring the overhead of matching an include pattern
return false;
} else {
// If includes is empty always return true
return CollectionUtils.isEmpty(includes) || singleWildcardMatch(value, includes);
}
}
public static boolean singleWildcardMatch(String s, List patterns) {
for (String pattern : CollectionUtils.toEmpty(patterns)) {
if (singleWildcardMatch(s, pattern)) {
return true;
}
}
return false;
}
/**
* Match {@code value} against {@code pattern} where {@code pattern} can optionally contain a single wildcard. If both are {@code null}
* return {@code true}. If one is {@code null} but not the other, return {@code false}. If neither is {@code null}, any {@code pattern}
* containing more than a single wildcard throws {@code IllegalArgumentException}.
*
*
*/
public static boolean singleWildcardMatch(String value, String pattern) {
if (value == null && pattern == null) {
// both are null
return true;
} else if (value != null && pattern == null) {
// pattern is null but value is not
return false;
} else if (value == null && pattern != null) {
// value is null but pattern is not
return false;
} else if (StringUtils.countMatches(pattern, Constants.WILDCARD) > 1) {
throw new IllegalArgumentException("Pattern [" + pattern + "] is not supported. Only one wildcard is allowed in the pattern");
} else if (pattern.equals(Constants.WILDCARD)) {
// neither one is null and pattern is the wildcard. Value is irrelevant
return true;
} else if (!StringUtils.contains(pattern, Constants.WILDCARD)) {
// Neither one is null and there is no wildcard in the pattern. They must match exactly
return StringUtils.equals(value, pattern);
} else {
int pos = StringUtils.indexOf(pattern, Constants.WILDCARD);
int suffixPos = pos + Constants.WILDCARD.length();
boolean nullPrefix = pos == 0;
boolean nullSuffix = suffixPos >= pattern.length();
String prefix = nullPrefix ? null : StringUtils.substring(pattern, 0, pos);
String suffix = nullSuffix ? null : StringUtils.substring(pattern, suffixPos);
boolean prefixMatch = nullPrefix || StringUtils.startsWith(value, prefix);
boolean suffixMatch = nullSuffix || StringUtils.endsWith(value, suffix);
return prefixMatch && suffixMatch;
}
}
/**
* Return property keys that should be included as a sorted list.
*/
public static final Properties getProperties(Properties properties, String include, String exclude) {
List keys = getSortedKeys(properties, include, exclude);
Properties newProperties = new Properties();
for (String key : keys) {
String value = properties.getProperty(key);
newProperties.setProperty(key, value);
}
return newProperties;
}
/**
* Return property keys that should be included as a sorted list.
*/
public static final List getSortedKeys(Properties properties, String include, String exclude) {
return getSortedKeys(properties, CollectionUtils.toEmptyList(include), CollectionUtils.toEmptyList(exclude));
}
/**
* Return property keys that should be included as a sorted list.
*/
public static final List getSortedKeys(Properties properties, List includes, List excludes) {
List keys = getSortedKeys(properties);
List includedKeys = new ArrayList();
for (String key : keys) {
if (include(key, includes, excludes)) {
includedKeys.add(key);
}
}
return includedKeys;
}
/**
* Return a sorted List of keys from properties that start with prefix
*/
public static final List getStartsWithKeys(Properties properties, String prefix) {
List keys = getSortedKeys(properties);
List matches = new ArrayList();
for (String key : keys) {
if (StringUtils.startsWith(key, prefix)) {
matches.add(key);
}
}
return matches;
}
/**
* Return the property keys as a sorted list.
*/
public static final List getSortedKeys(Properties properties) {
List keys = new ArrayList(properties.stringPropertyNames());
Collections.sort(keys);
return keys;
}
public static final String toString(Properties properties) {
List keys = getSortedKeys(properties);
StringBuilder sb = new StringBuilder();
for (String key : keys) {
String value = Str.flatten(properties.getProperty(key));
sb.append(key + "=" + value + "\n");
}
return sb.toString();
}
public static final void info(Properties properties) {
properties = toEmpty(properties);
logger.info("--- Displaying {} properties ---\n\n{}", properties.size(), toString(properties));
}
public static final void debug(Properties properties) {
properties = toEmpty(properties);
logger.debug("--- Displaying {} properties ---\n\n{}", properties.size(), toString(properties));
}
/**
* Store the properties to the indicated file using the platform default encoding.
*/
public static final void store(Properties properties, File file) {
store(properties, file, null);
}
/**
* Store the properties to the indicated file using the indicated encoding.
*/
public static final void store(Properties properties, File file, String encoding) {
store(properties, file, encoding, null);
}
/**
* Store the properties to the indicated file using the indicated encoding with the indicated comment appearing at the top of the file.
*/
public static final void store(Properties properties, File file, String encoding, String comment) {
OutputStream out = null;
Writer writer = null;
try {
out = FileUtils.openOutputStream(file);
String path = file.getCanonicalPath();
boolean xml = isXml(path);
Properties sorted = getSortedProperties(properties);
comment = getComment(encoding, comment, xml);
if (xml) {
logger.info("Storing XML properties - [{}] encoding={}", path, StringUtils.defaultIfBlank(encoding, DEFAULT_ENCODING));
if (encoding == null) {
sorted.storeToXML(out, comment);
} else {
sorted.storeToXML(out, comment, encoding);
}
} else {
writer = LocationUtils.getWriter(out, encoding);
logger.info("Storing properties - [{}] encoding={}", path, StringUtils.defaultIfBlank(encoding, DEFAULT_ENCODING));
sorted.store(writer, comment);
}
} catch (IOException e) {
throw new IllegalStateException("Unexpected IO error", e);
} finally {
IOUtils.closeQuietly(writer);
IOUtils.closeQuietly(out);
}
}
/**
* Return a new properties object containing the properties from getEnvAsProperties() and
* System.getProperties(). Properties from System.getProperties() override properties from
* getEnvAsProperties if there are duplicates.
*/
public static final Properties getGlobalProperties() {
return getProperties(Constants.DEFAULT_GLOBAL_PROPERTIES_MODE);
}
/**
* Return a new properties object containing the properties passed in, plus any properties returned by getEnvAsProperties()
* and System.getProperties(). Properties from getEnvAsProperties() override properties and
* properties from System.getProperties() override everything.
*/
public static final Properties getGlobalProperties(Properties properties) {
return getProperties(properties, Constants.DEFAULT_GLOBAL_PROPERTIES_MODE);
}
/**
* Return a new properties object containing the properties passed in, plus any global properties as requested. If mode is
* NONE the new properties are a duplicate of the properties passed in. If mode is ENVIRONMENT
* the new properties contain the original properties plus any properties returned by getEnvProperties(). If
* mode is SYSTEM the new properties contain the original properties plus System.getProperties().
* If mode is BOTH the new properties contain the original properties plus getEnvProperties() and
* System.getProperties().
*/
public static final Properties getProperties(Properties properties, GlobalPropertiesMode mode) {
Properties newProperties = duplicate(properties);
List modifiers = getPropertyProcessors(mode);
for (PropertyProcessor modifier : modifiers) {
modifier.process(newProperties);
}
return newProperties;
}
/**
* Return a new properties object containing global properties as requested. If mode is NONE the new
* properties are empty. If mode is ENVIRONMENT the new properties contain the properties returned by
* getEnvProperties(). If mode is SYSTEM the new properties contain
* System.getProperties(). If mode is BOTH the new properties contain
* getEnvProperties plus System.getProperties() with system properties overriding environment variables if the
* same case sensitive property key is supplied in both places.
*/
public static final Properties getProperties(GlobalPropertiesMode mode) {
return getProperties(new Properties(), mode);
}
/**
* Search global properties to find a value for key according to the mode passed in.
*/
public static final String getProperty(String key, GlobalPropertiesMode mode) {
return getProperty(key, new Properties(), mode);
}
/**
* Search properties plus global properties to find a value for key according to the mode passed in. If the
* property is present in both, the value from the global properties is returned.
*/
public static final String getProperty(String key, Properties properties, GlobalPropertiesMode mode) {
return getProperties(properties, mode).getProperty(key);
}
/**
* Return modifiers that add environment variables, system properties, or both, according to the mode passed in.
*/
public static final List getPropertyProcessors(GlobalPropertiesMode mode) {
List processors = new ArrayList();
switch (mode) {
case NONE:
return processors;
case ENVIRONMENT:
processors.add(new AddPropertiesProcessor(getEnvAsProperties()));
return processors;
case SYSTEM:
processors.add(new AddPropertiesProcessor(System.getProperties()));
return processors;
case BOTH:
processors.add(new AddPropertiesProcessor(getEnvAsProperties()));
processors.add(new AddPropertiesProcessor(System.getProperties()));
return processors;
default:
throw new IllegalStateException(mode + " is unknown");
}
}
/**
* Convert the Map to a Properties object.
*/
public static final Properties convert(Map map) {
Properties props = new Properties();
for (String key : map.keySet()) {
String value = map.get(key);
props.setProperty(key, value);
}
return props;
}
/**
* Return a new properties object that duplicates the properties passed in.
*/
public static final Properties duplicate(Properties properties) {
Properties newProperties = new Properties();
newProperties.putAll(properties);
return newProperties;
}
/**
* Return a new properties object containing environment variables as properties prefixed with env
*/
public static Properties getEnvAsProperties() {
return getEnvAsProperties(ENV_PREFIX);
}
/**
* Return a new properties object containing environment variables as properties prefixed with prefix
*/
public static Properties getEnvAsProperties(String prefix) {
Properties properties = convert(System.getenv());
return getPrefixedProperties(properties, prefix);
}
/**
* Return true if, and only if, location ends with .xml (case insensitive).
*/
public static final boolean isXml(String location) {
return StringUtils.endsWithIgnoreCase(location, XML_EXTENSION);
}
/**
* Return a new Properties object loaded from location.
*/
public static final Properties load(String location) {
return load(location, null);
}
/**
* Return a new Properties object loaded from location using encoding.
*/
public static final Properties load(String location, String encoding) {
InputStream in = null;
Reader reader = null;
try {
Properties properties = new Properties();
boolean xml = isXml(location);
if (xml) {
in = LocationUtils.getInputStream(location);
logger.info("Loading XML properties - [{}]", location);
properties.loadFromXML(in);
} else {
logger.info("Loading properties - [{}] encoding={}", location, StringUtils.defaultIfBlank(encoding, DEFAULT_ENCODING));
reader = LocationUtils.getBufferedReader(location, encoding);
properties.load(reader);
}
return properties;
} catch (IOException e) {
throw new IllegalStateException("Unexpected IO error", e);
} finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(reader);
}
}
/**
* Return a new Properties object containing properties prefixed with prefix. If prefix is blank,
* the new properties object duplicates the properties passed in.
*/
public static final Properties getPrefixedProperties(Properties properties, String prefix) {
if (StringUtils.isBlank(prefix)) {
return duplicate(properties);
}
Properties newProperties = new Properties();
for (String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
String newKey = StringUtils.startsWith(key, prefix + ".") ? key : prefix + "." + key;
newProperties.setProperty(newKey, value);
}
return newProperties;
}
/**
* Return a new properties object where the keys have been converted to upper case and periods have been replaced with an underscore.
*/
public static final Properties reformatKeysAsEnvVars(Properties properties) {
Properties newProperties = new Properties();
for (String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
String newKey = StringUtils.upperCase(StringUtils.replace(key, ".", "-"));
newProperties.setProperty(newKey, value);
}
return newProperties;
}
/**
* Before setting the newValue, check to see if there is a conflict with an existing value. If there is no existing value, add the
* property. If there is a conflict, check propertyOverwriteMode to make sure we have permission to override the value.
*/
public static final void addOrOverrideProperty(Properties properties, String key, String newValue, Mode propertyOverwriteMode) {
String oldValue = properties.getProperty(key);
if (StringUtils.equals(newValue, oldValue)) {
// Nothing to do! New value is the same as old value.
return;
}
boolean overwrite = !StringUtils.isBlank(oldValue);
// TODO Yuck! Do something smarter here
String logNewValue = newValue;
String logOldValue = oldValue;
if (StringUtils.containsIgnoreCase(key, "password")) {
logNewValue = LoggerUtils.getPassword(null, logNewValue);
logOldValue = LoggerUtils.getPassword(null, logOldValue);
}
if (overwrite) {
// This property already has a value, and it is different from the new value
// Check to make sure we are allowed to override the old value before doing so
Object[] args = new Object[] { key, Str.flatten(logNewValue), Str.flatten(logOldValue) };
ModeUtils.validate(propertyOverwriteMode, "Overriding [{}={}] was [{}]", args, "Override of existing property [" + key + "] is not allowed.");
} else {
// There is no existing value for this key
logger.info("Adding [{}={}]", key, Str.flatten(logNewValue));
}
properties.setProperty(key, newValue);
}
private static final String getDefaultComment(String encoding, boolean xml) {
if (encoding == null) {
if (xml) {
// Java defaults XML properties files to UTF-8 if no encoding is provided
return "encoding.default=" + DEFAULT_XML_ENCODING;
} else {
// For normal properties files the platform default encoding is used
return "encoding.default=" + DEFAULT_ENCODING;
}
} else {
return "encoding.specified=" + encoding;
}
}
private static final String getComment(String comment, String encoding, boolean xml) {
if (StringUtils.isBlank(comment)) {
return getDefaultComment(encoding, xml);
} else {
return comment + "\n#" + getDefaultComment(encoding, xml);
}
}
/**
* This is private because SortedProperties does not fully honor the contract for Properties
*/
private static final SortedProperties getSortedProperties(Properties properties) {
SortedProperties sp = new PropertyUtils().new SortedProperties();
sp.putAll(properties);
return sp;
}
/**
* This is private since it does not honor the full contract for Properties. PropertyUtils uses it internally
* to store properties in sorted order.
*/
private class SortedProperties extends Properties {
private static final long serialVersionUID = 1330825236411537386L;
/**
* Properties.storeToXML() uses keySet()
*/
@Override
public Set