/*
* Copyright 2013 the original author or authors.
*
* 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 ratpack.util.internal;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteSource;
import com.google.common.io.Files;
import com.google.common.io.Resources;
import java.io.*;
import java.net.*;
import java.util.List;
import java.util.Properties;
import static java.lang.String.format;
/**
* A delegate for {@link java.util.Properties} that can coerce values to various types.
*/
public class TypeCoercingProperties {
private final Properties delegate;
private final ClassLoader classLoader;
public TypeCoercingProperties(Properties delegate) {
this(delegate, TypeCoercingProperties.class.getClassLoader());
}
public TypeCoercingProperties(Properties delegate, ClassLoader classLoader) {
this.delegate = delegate;
this.classLoader = classLoader;
}
/**
* Gets a property value as a String, substituting a default if the property does not exist.
*
* @param key the property key.
* @param defaultValue the value to use if the property does not exist.
* @return the property value as a String or <code>defaultValue</code> if it does not exist.
* @see Properties#getProperty(String, String)
*/
public String asString(String key, String defaultValue) {
return delegate.getProperty(key, defaultValue);
}
/**
* Gets a property value as a boolean, substituting a default if the property does not exist.
*
* @param key the property key.
* @param defaultValue the value to use if the property does not exist.
* @return the property value coerced to a boolean as specified by {@link Boolean#parseBoolean(String)} or <code>defaultValue</code> if it does not exist.
*/
public boolean asBoolean(String key, boolean defaultValue) {
return Boolean.parseBoolean(delegate.getProperty(key, Boolean.toString(defaultValue)));
}
/**
* Gets a property value as an int, substituting a default if the property does not exist.
*
* @param key the property key.
* @param defaultValue the value to use if the property does not exist.
* @return the property value coerced to an int as specified by {@link Integer#parseInt(String)} or <code>defaultValue</code> if it does not exist.
*/
public int asInt(String key, int defaultValue) {
return Integer.parseInt(delegate.getProperty(key, Integer.toString(defaultValue)));
}
/**
* Gets a property value as an long, substituting a default if the property does not exist.
*
* @param key the property key.
* @param defaultValue the value to use if the property does not exist.
* @return the property value coerced to an long as specified by {@link Long#parseLong(String)} or <code>defaultValue</code> if it does not exist.
*/
public long asLong(String key, long defaultValue) {
return Long.parseLong(delegate.getProperty(key, Long.toString(defaultValue)));
}
/**
* Gets a property value as a URI.
*
* @param key the property key.
* @return the URI represented by the property value or <code>null</code> if the property does not exist.
* @throws URISyntaxException if the property value is not a valid URI.
*/
public URI asURI(String key) throws URISyntaxException {
URI uri = null;
String uriString = delegate.getProperty(key);
if (uriString != null) {
uri = new URI(uriString);
}
return uri;
}
/**
* Gets a property value as an InetAddress.
*
* @param key the property key.
* @return the InetAddress represented by the property value or <code>null</code> if the property does not exist.
* @throws UnknownHostException if the property value is not a valid address.
*/
public InetAddress asInetAddress(String key) throws UnknownHostException {
String addressString = delegate.getProperty(key);
if (addressString == null) {
return null;
} else {
return InetAddress.getByName(addressString);
}
}
/**
* Gets a property value as a List of Strings. Each element of the returned List is trimmed of leading and trailing whitespace. Empty elements are omitted from the List.
*
* @param key the property key.
* @return a List of Strings created by treating the property value as a comma-separated list or an empty List if the property does not exist.
*/
public List<String> asList(String key) {
String delimitedValues = delegate.getProperty(key, "");
ImmutableList.Builder<String> trimmed = ImmutableList.builder();
for (String value : delimitedValues.split(",")) {
value = value.trim();
if (!value.isEmpty()) {
trimmed.add(value);
}
}
return trimmed.build();
}
/**
* Gets a property value as a ByteSource. The property value can be any of:
* <ul>
* <li>An absolute file path to a file that exists.</li>
* <li>A valid URI.</li>
* <li>A classpath resource path loaded via the ClassLoader passed to the constructor.</li>
* </ul>
*
* @param key the property key.
* @return a ByteSource or {@code null} if the property does not exist.
* @throws java.lang.IllegalArgumentException if the property value cannot be resolved to a byte source.
*/
public ByteSource asByteSource(String key) {
ByteSource byteSource = null;
String path = delegate.getProperty(key);
if (path != null) {
// try to treat it as a File path
File file = new File(path);
if (file.isFile()) {
byteSource = Files.asByteSource(file);
} else {
// try to treat it as a URL
try {
URL url = new URL(path);
byteSource = Resources.asByteSource(url);
} catch (MalformedURLException e) {
// try to treat it as a resource path
byteSource = Resources.asByteSource(Resources.getResource(path));
}
}
}
return byteSource;
}
/**
* Gets a property value as an InputStream. The property value can be any of:
* <ul>
* <li>An absolute file path to a file that exists.</li>
* <li>A valid URI.</li>
* <li>A classpath resource path loaded via the ClassLoader passed to the constructor.</li>
* </ul>
*
* @param key the property key.
* @return an InputStream or <code>null</code> if the property does not exist.
* @throws FileNotFoundException if the property value cannot be resolved to a stream source.
*/
public InputStream asStream(String key) throws IOException {
InputStream stream = null;
String path = delegate.getProperty(key);
if (path != null) {
// try to treat it as a File path
File file = new File(path);
if (file.isFile()) {
stream = new FileInputStream(file);
} else {
// try to treat it as a URL
try {
URL url = new URL(path);
stream = url.openStream();
} catch (MalformedURLException e) {
// try to treat it as a resource path
stream = classLoader.getResourceAsStream(path);
if (stream == null) {
throw new FileNotFoundException(path);
}
}
}
}
return stream;
}
/**
* Gets a property value as a Class. The property value should be a fully-qualified class name that can be loaded via the ClassLoader passed to the constructor. The class should be an instance of the <code>type</code> parameter – typically an interface.
*
* @param key the property key.
* @param type the expected type of the Class, typically the interface it should implement.
* @return a Class or <code>null</code> if the property does not exist.
* @throws ClassNotFoundException if no Class is found matching the name from the property value.
* @throws ClassCastException if a Class is loaded but it does not implement the <code>type</code> interface.
*/
@SuppressWarnings("unchecked")
public <T> Class<T> asClass(String key, Class<T> type) throws ClassNotFoundException {
String className = delegate.getProperty(key);
if (className == null) {
return null;
}
Class<?> untypedClass = classLoader.loadClass(className);
if (!type.isAssignableFrom(untypedClass)) {
throw new ClassCastException(format("Class '%s' does not implement '%s", className, type.getName()));
}
return (Class<T>) classLoader.loadClass(className);
}
}