/*
* Licensed to Digitas France under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
*
* 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 fr.cedrik.util;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
/**
* Loads a properties file from filesystem or classpath.<br>
* System properties override properties values.<br>
* Convenience type conversion methods.
*
* @author Cédrik LIME
* @see Properties
* @see "http://commons.apache.org/configuration/"
* @see PropertyEditor
*/
@SuppressWarnings("serial")
public class ExtendedProperties extends Properties {
/**
* Creates an empty property list with no default values.
*/
public ExtendedProperties() {
super();
}
/**
* Creates an empty property list with the specified defaults.
*
* @param defaults the defaults.
*/
public ExtendedProperties(Properties defaults) {
super(defaults);
}
/**
* Loads the given file from the filesystem or the classpath.
*
* @see Properties#load(InputStream)
*/
public void load(String file) throws IOException {
InputStream in = null;
// load from filesystem
try {
in = new FileInputStream(new File(file));
} catch (FileNotFoundException ignore) {
}
if (in != null) {
try {
load(in);
// } catch (IOException e) {
// throw new IllegalStateException("Error while loading file from filesystem: " + file, e);
} finally {
IOUtils.closeQuietly(in);
}
} else {
if (Thread.currentThread().getContextClassLoader() != null) {
in = Thread.currentThread().getContextClassLoader().getResourceAsStream(file);
}
if (in == null) {
in = this.getClass().getResourceAsStream(file);
}
if (in != null) {
// load from classpath
try {
load(in);
// } catch (IOException e) {
// throw new IllegalStateException("Error while loadind file from classpath: " + file, e);
} finally {
IOUtils.closeQuietly(in);
}
} else {
// error
throw new FileNotFoundException("Can not find file neither in filesystem nor classpath: " + file);
}
}
}
/************************************************************************/
/**
* {@inheritDoc}
* <p>
* Looks up in System properties before looking up in this property list.
*/
@Override
public String getProperty(String key) {
String value = System.getProperty(key);
if (value == null) {
value = super.getProperty(key);
}
return value;
}
public <T> T get(String key, Class<T> targetType) {
String valueStr = getProperty(key);
return convert(valueStr, targetType);
}
public <T> T get(String key, T defaultValueNotNull) {
if (defaultValueNotNull == null) {
throw new NullPointerException("defaultValue can not be null");
}
String val = getProperty(key);
return (val == null) ? defaultValueNotNull : convert(val, (Class<T>)defaultValueNotNull.getClass());
}
/**
* convert via a {@link java.beans.PropertyEditor}
*/
// see also org.springframework.beans.propertyeditors
// http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/validation.html
// see also org.apache.commons.configuration.PropertyConverter
protected <T> T convert(String valueStr, Class<T> targetType) {
PropertyEditor propertyEditor = PropertyEditorManager.findEditor(targetType);
if (propertyEditor == null) {
throw new IllegalArgumentException("Can not find a PropertyEditor for class " + targetType);
}
propertyEditor.setAsText(valueStr);
T value = (T) propertyEditor.getValue();
return value;
}
public String getString(String key) {
return getProperty(key);
}
public String getString(String key, String defaultValue) {
return getProperty(key, defaultValue);
}
public boolean getBoolean(String key) {
return Boolean.parseBoolean(getProperty(key));
}
public boolean getBoolean(String key, boolean defaultValue) {
String val = getProperty(key);
return (val == null) ? defaultValue : Boolean.parseBoolean(val);
}
public byte getByte(String key) {
return Byte.parseByte(getProperty(key));
}
public byte getByte(String key, byte defaultValue) {
String val = getProperty(key);
return (val == null) ? defaultValue : Byte.parseByte(val);
}
public short getShort(String key) {
return Short.parseShort(getProperty(key));
}
public short getShort(String key, short defaultValue) {
String val = getProperty(key);
return (val == null) ? defaultValue : Short.parseShort(val);
}
public int getInt(String key) {
return Integer.parseInt(getProperty(key));
}
public int getInt(String key, int defaultValue) {
String val = getProperty(key);
return (val == null) ? defaultValue : Integer.parseInt(val);
}
public long getLong(String key) {
return Long.parseLong(getProperty(key));
}
public long getLong(String key, long defaultValue) {
String val = getProperty(key);
return (val == null) ? defaultValue : Long.parseLong(val);
}
public float getFloat(String key) {
return Float.parseFloat(getProperty(key));
}
public float getFloat(String key, float defaultValue) {
String val = getProperty(key);
return (val == null) ? defaultValue : Float.parseFloat(val);
}
public double getDouble(String key) {
return Double.parseDouble(getProperty(key));
}
public double getDouble(String key, double defaultValue) {
String val = getProperty(key);
return (val == null) ? defaultValue : Double.parseDouble(val);
}
public String[] getStringArray(String key) {
return getStringArray(key, ',');
}
public String[] getStringArray(String key, char separatorChar) {
String val = getProperty(key);
return StringUtils.split(val, separatorChar);
}
//TODO need to pass a convertor to convert from List<String> to List<T>
// public List<String> getList(String key) {
// return getList(key, ',');
// }
// public List<String> getStringList(String key, char separatorChar) {
// return Arrays.asList(getStringArray(key, separatorChar));
// }
/**
* Performance note: this is a convenience method, not intended for intensive usage.
* Please cache your own {@link MessageFormat} instance for performance.
*/
public String getMessage(String key, Object...arguments) {
return MessageFormat.format(getString(key), arguments);
}
}