/*
* The MIT License
*
* Copyright 2015 Ahseya.
*
* Permission is hereby granted, free of charge, to any person obtaining a copyOf
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copyOf, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.github.horrorho.liquiddonkey.util;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import net.jcip.annotations.Immutable;
import net.jcip.annotations.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Props. Lightweight properties helper.
*
* @author Ahseya
* @param <E>
*/
@Immutable
@ThreadSafe
public final class Props<E extends Enum<E>> {
public static <E extends Enum<E>> Props<E> from(Properties properties) {
return new Props<>(properties, defaultDateTimeFormatter);
}
public static <E extends Enum<E>> Props<E> from(Properties properties, DateTimeFormatter dateTimeFormatter) {
return new Props<>(properties, dateTimeFormatter);
}
public static Properties flatCopy(Properties properties) {
if (properties == null) {
return null;
}
Enumeration<?> propertyNames = properties.propertyNames();
Properties copy = new Properties();
while (propertyNames.hasMoreElements()) {
Object propertyName = propertyNames.nextElement();
copy.setProperty(propertyName.toString(), properties.getProperty(propertyName.toString()));
}
return copy;
}
private static final Logger logger = LoggerFactory.getLogger(Props.class);
private static final DateTimeFormatter defaultDateTimeFormatter = DateTimeFormatter.BASIC_ISO_DATE;
private final Properties properties;
private final DateTimeFormatter dateTimeFormatter;
Props(Properties properties, DateTimeFormatter dateTimeFormatter) {
this.properties = Objects.requireNonNull(flatCopy(properties));
this.dateTimeFormatter = Objects.requireNonNull(dateTimeFormatter);
}
Properties properties() {
return flatCopy(properties);
}
public boolean containsProperty(E property) {
return property == null
? false
: properties.containsKey(property.name());
}
public String getProperty(E property) {
return containsProperty(property)
? properties.getProperty(property.name())
: null;
}
public <T> T getProperty(E property, Function<String, T> function) {
return function.apply(getProperty(property));
}
public List<String> asList(String val) {
return val == null
? null
: Arrays.asList(val.split("\\s"));
}
public <T> List<T> asList(String val, Function<String, T> function) {
List<String> vals = asList(val);
return vals == null
? null
: vals.stream()
.map(function::apply)
.collect(Collectors.toList());
}
public Boolean asBoolean(String val) {
return Boolean.parseBoolean(val);
}
public String isHex(String val) {
return val == null
? null
: val.matches("^[0-9a-fA-F]+$")
? val
: illegalArgumentException("bad hex: " + val);
}
public Double asDouble(String val) {
return asNumber(val, Double::parseDouble);
}
public Integer asInteger(String val) {
return asNumber(val, Integer::parseInt);
}
public Long asLong(String val) {
return asNumber(val, Long::parseLong);
}
public <T extends Number> T asNumber(String val, Function<String, T> parser) {
return parse(
val,
parser,
NumberFormatException.class,
() -> illegalArgumentException("bad number: " + val));
}
public Long asTimestamp(String val) {
return parse(
val,
date -> LocalDate.parse(date, dateTimeFormatter).atStartOfDay(ZoneId.systemDefault()).toEpochSecond(),
DateTimeParseException.class,
() -> illegalArgumentException("bad date: " + val));
}
private <T, E extends Exception> T
parse(String value, Function<String, T> parser, Class<E> exceptionType, Supplier<T> exception) {
try {
return value == null
? null
: parser.apply(value);
} catch (RuntimeException ex) {
if (!(exceptionType.isAssignableFrom(ex.getClass()))) {
throw ex;
}
logger.warn("-- parse() > exception: ", ex);
return exception.get();
}
}
private <T> T illegalArgumentException(String message) {
throw new IllegalArgumentException(message);
}
@Override
public String toString() {
return properties.toString();
}
}