/**
* Copyright 2016 LinkedIn Corp. All rights reserved.
*
* 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.
*/
package com.github.ambry.config;
import java.math.BigDecimal;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Verifiable properties for configs
*/
public class VerifiableProperties {
private final HashSet<String> referenceSet = new HashSet<String>();
private final Properties props;
protected Logger logger = LoggerFactory.getLogger(getClass());
public VerifiableProperties(Properties props) {
this.props = props;
}
public boolean containsKey(String name) {
return props.containsKey(name);
}
public String getProperty(String name) {
String value = props.getProperty(name);
referenceSet.add(name);
return value;
}
/**
* Read a required integer property value or throw an exception if no such property is found
*/
public int getInt(String name) {
return Integer.parseInt(getString(name));
}
public int getIntInRange(String name, int start, int end) {
if (!containsKey(name)) {
throw new IllegalArgumentException("Missing required property '" + name + "'");
}
return getIntInRange(name, -1, start, end);
}
/**
* Read an integer from the properties instance
* @param name The property name
* @param defaultVal The default value to use if the property is not found
* @return the integer value
*/
public int getInt(String name, int defaultVal) {
return getIntInRange(name, defaultVal, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
public Integer getInteger(String name, Integer defaultVal) {
Integer v;
if (containsKey(name)) {
v = Integer.parseInt(getProperty(name));
} else {
v = defaultVal;
}
return v;
}
public Short getShort(String name, Short defaultVal) {
return getShortInRange(name, defaultVal, Short.MIN_VALUE, Short.MAX_VALUE);
}
/**
* Read an integer from the properties instance. Throw an exception
* if the value is not in the given range (inclusive)
* @param name The property name
* @param defaultVal The default value to use if the property is not found
* @param start The start of the range in which the value must fall (inclusive)
* @param end The end of the range in which the value must fall
* @throws IllegalArgumentException If the value is not in the given range
* @return the integer value
*/
public int getIntInRange(String name, int defaultVal, int start, int end) {
int v = 0;
if (containsKey(name)) {
v = Integer.parseInt(getProperty(name));
} else {
v = defaultVal;
}
if (v >= start && v <= end) {
return v;
} else {
throw new IllegalArgumentException(
name + " has value " + v + " which is not in the range " + start + "-" + end + ".");
}
}
public Short getShortInRange(String name, Short defaultVal, Short start, Short end) {
Short v = 0;
if (containsKey(name)) {
v = Short.parseShort(getProperty(name));
} else {
v = defaultVal;
}
if (v >= start && v <= end) {
return v;
} else {
throw new IllegalArgumentException(
name + " has value " + v + " which is not in the range " + start + "-" + end + ".");
}
}
public Double getDoubleInRange(String name, Double defaultVal, Double start, Double end) {
Double v = 0.0;
if (containsKey(name)) {
v = Double.parseDouble(getProperty(name));
} else {
v = defaultVal;
}
// use big decimal for double comparison
BigDecimal startDecimal = new BigDecimal(start);
BigDecimal endDecimal = new BigDecimal(end);
BigDecimal value = new BigDecimal(v);
if (value.compareTo(startDecimal) >= 0 && value.compareTo(endDecimal) <= 0) {
return v;
} else {
throw new IllegalArgumentException(
name + " has value " + v + " which is not in range " + start + "-" + end + ".");
}
}
/**
* Read a required long property value or throw an exception if no such property is found
*/
public long getLong(String name) {
return Long.parseLong(getString(name));
}
/**
* Read an long from the properties instance
* @param name The property name
* @param defaultVal The default value to use if the property is not found
* @return the long value
*/
public long getLong(String name, long defaultVal) {
return getLongInRange(name, defaultVal, Long.MIN_VALUE, Long.MAX_VALUE);
}
/**
* Read an long from the properties instance. Throw an exception
* if the value is not in the given range (inclusive)
* @param name The property name
* @param defaultVal The default value to use if the property is not found
* @param start The start of the range in which the value must fall (inclusive)
* @param end The end of the range in which the value must fall
* @throws IllegalArgumentException If the value is not in the given range
* @return the long value
*/
public long getLongInRange(String name, long defaultVal, long start, long end) {
long v = 0;
if (containsKey(name)) {
v = Long.parseLong(getProperty(name));
} else {
return defaultVal;
}
if (v >= start && v <= end) {
return v;
} else {
throw new IllegalArgumentException(
name + " has value " + v + " which is not in the range " + start + "-" + end + ".");
}
}
/**
* Get a required argument as a double
* @param name The property name
* @return the value
* @throw IllegalArgumentException If the given property is not present
*/
public double getDouble(String name) {
return Double.parseDouble(getString(name));
}
/**
* Get an optional argument as a double
* @param name The property name
* @default The default value for the property if not present
*/
public double getDouble(String name, double defaultVal) {
if (containsKey(name)) {
return getDouble(name);
} else {
return defaultVal;
}
}
/**
* Read a boolean value from the properties instance
* @param name The property name
* @param defaultVal The default value to use if the property is not found
* @return the boolean value
*/
public boolean getBoolean(String name, boolean defaultVal) {
String v = "";
if (!containsKey(name)) {
return defaultVal;
} else {
v = getProperty(name);
if (v.compareTo("true") == 0 || v.compareTo("false") == 0) {
return Boolean.parseBoolean(v);
} else {
throw new IllegalArgumentException(name + " has value " + v + " which is not true or false.");
}
}
}
public boolean getBoolean(String name) {
return Boolean.parseBoolean(getString(name));
}
/**
* Get a string property, or, if no such property is defined, return the given default value
*/
public String getString(String name, String defaultVal) {
if (containsKey(name)) {
return getProperty(name);
} else {
return defaultVal;
}
}
/**
* Get a string property or throw and exception if no such property is defined.
*/
public String getString(String name) {
if (!containsKey(name)) {
throw new IllegalArgumentException("Missing required property '" + name + "'");
} else {
return getProperty(name);
}
}
public void verify() {
logger.info("Verifying properties");
Enumeration keys = props.propertyNames();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
if (!referenceSet.contains(key)) {
logger.warn("Property {} is not valid", key);
} else {
logger.info("Property {} is overridden to {}", key, props.getProperty(key.toString()));
}
}
}
public String toString() {
return props.toString();
}
}