io.datakernel.config.ConfigConverters Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of datakernel-boot Show documentation
Show all versions of datakernel-boot Show documentation
An intelligent way of booting complex applications and services according to their dependencies
/*
* Copyright (C) 2015-2018 SoftIndex LLC.
*
* 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 io.datakernel.config;
import io.datakernel.async.EventloopTaskScheduler;
import io.datakernel.async.RetryPolicy;
import io.datakernel.eventloop.FatalErrorHandler;
import io.datakernel.eventloop.InetAddressRange;
import io.datakernel.eventloop.ThrottlingController;
import io.datakernel.exception.ParseException;
import io.datakernel.net.DatagramSocketSettings;
import io.datakernel.net.ServerSocketSettings;
import io.datakernel.net.SocketSettings;
import io.datakernel.util.MemSize;
import io.datakernel.util.SimpleThreadFactory;
import io.datakernel.util.StringFormatUtils;
import io.datakernel.util.Utils;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.*;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.regex.Pattern;
import static io.datakernel.eventloop.FatalErrorHandlers.*;
import static io.datakernel.eventloop.ThrottlingController.INITIAL_KEYS_PER_SECOND;
import static io.datakernel.eventloop.ThrottlingController.INITIAL_THROTTLING;
import static io.datakernel.net.ServerSocketSettings.DEFAULT_BACKLOG;
import static io.datakernel.util.Preconditions.checkArgument;
import static io.datakernel.util.Utils.apply;
import static io.datakernel.util.Utils.applyIfNotNull;
import static java.lang.Integer.parseInt;
import static java.util.Collections.emptyList;
import static java.util.regex.Pattern.compile;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
@SuppressWarnings({"unused", "WeakerAccess"})
public final class ConfigConverters {
private ConfigConverters() {
}
public static ConfigConverter ofLocalDate() {
return new SimpleConfigConverter() {
@Override
protected LocalDate fromString(String string) {
return LocalDate.parse(string);
}
@Override
protected String toString(LocalDate value) {
return value.toString();
}
};
}
public static ConfigConverter ofLocalTime() {
return new SimpleConfigConverter() {
@Override
protected LocalTime fromString(String string) {
return LocalTime.parse(string);
}
@Override
protected String toString(LocalTime value) {
return value.toString();
}
};
}
public static ConfigConverter ofLocalDateTime() {
return new SimpleConfigConverter() {
@Override
protected LocalDateTime fromString(String string) {
return StringFormatUtils.parseLocalDateTime(string);
}
@Override
protected String toString(LocalDateTime value) {
return StringFormatUtils.formatLocalDateTime(value);
}
};
}
public static ConfigConverter ofPeriod() {
return new SimpleConfigConverter() {
@Override
protected Period fromString(String string) {
return StringFormatUtils.parsePeriod(string);
}
@Override
protected String toString(Period value) {
return StringFormatUtils.formatPeriod(value);
}
};
}
/**
* @return config converter with days in period
*/
public static ConfigConverter ofPeriodAsDays() {
return ofPeriod().transform(Period::getDays, Period::ofDays);
}
public static ConfigConverter ofDuration() {
return new SimpleConfigConverter() {
@Override
protected Duration fromString(String string) {
return StringFormatUtils.parseDuration(string);
}
@Override
protected String toString(Duration value) {
return StringFormatUtils.formatDuration(value);
}
};
}
/**
* @return config converter with millis in duration
*/
public static ConfigConverter ofDurationAsMillis() {
return ofDuration().transform(Duration::toMillis, Duration::ofMillis);
}
public static ConfigConverter ofInstant() {
return new SimpleConfigConverter() {
@Override
protected Instant fromString(String string) {
return StringFormatUtils.parseInstant(string);
}
@Override
protected String toString(Instant value) {
return StringFormatUtils.formatInstant(value);
}
};
}
/**
* @return config converter with epoch millis in instant
*/
public static ConfigConverter ofInstantAsEpochMillis() {
return ofInstant().transform(Instant::toEpochMilli, Instant::ofEpochMilli);
}
public static ConfigConverter ofString() {
return new ConfigConverter() {
@Override
public String get(Config config, String defaultValue) {
return config.getValue(defaultValue);
}
@Override
public String get(Config config) {
return get(config, "");
}
};
}
public static ConfigConverter ofNullableString() {
return new SimpleConfigConverter() {
@Override
protected String fromString(String string) {
return string;
}
@Override
protected String toString(String value) {
return value;
}
};
}
public static ConfigConverter ofByte() {
return new SimpleConfigConverter() {
@Override
protected Byte fromString(String string) {
return Byte.valueOf(string);
}
@Override
protected String toString(Byte value) {
return Byte.toString(value);
}
};
}
public static ConfigConverter ofInteger() {
return new SimpleConfigConverter() {
@Override
protected Integer fromString(String string) {
return Integer.valueOf(string);
}
@Override
protected String toString(Integer value) {
return Integer.toString(value);
}
};
}
public static ConfigConverter ofLong() {
return new SimpleConfigConverter() {
@Override
public Long fromString(String string) {
return Long.parseLong(string);
}
@Override
public String toString(Long value) {
return Long.toString(value);
}
};
}
public static ConfigConverter ofFloat() {
return new SimpleConfigConverter() {
@Override
public Float fromString(String string) {
return Float.parseFloat(string);
}
@Override
public String toString(Float value) {
return Float.toString(value);
}
};
}
public static ConfigConverter ofDouble() {
return new SimpleConfigConverter() {
@Override
public Double fromString(String string) {
return Double.parseDouble(string);
}
@Override
public String toString(Double value) {
return Double.toString(value);
}
};
}
public static ConfigConverter ofBoolean() {
return new SimpleConfigConverter() {
@Override
public Boolean fromString(String string) {
return Boolean.parseBoolean(string);
}
@Override
public String toString(Boolean value) {
return Boolean.toString(value);
}
};
}
public static > SimpleConfigConverter ofEnum(Class enumClass) {
Class enumClass1 = enumClass;
return new SimpleConfigConverter() {
private final Class enumClass = enumClass1;
@Override
public E fromString(String string) {
return Enum.valueOf(enumClass, string);
}
@Override
public String toString(E value) {
return value.name();
}
};
}
public static ConfigConverter ofClass() {
return new SimpleConfigConverter() {
@Override
public Class fromString(String string) {
try {
return Class.forName(string);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public String toString(Class value) {
return value.getName();
}
};
}
public static ConfigConverter ofInetAddress() {
return new SimpleConfigConverter() {
@Override
public InetAddress fromString(String address) {
try {
return InetAddress.getByName(address);
} catch (UnknownHostException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public String toString(InetAddress value) {
return Arrays.toString(value.getAddress());
}
};
}
public static ConfigConverter ofInetSocketAddress() {
return new SimpleConfigConverter() {
@Override
public InetSocketAddress fromString(String addressPort) {
int portPos = addressPort.lastIndexOf(':');
if (portPos == -1) {
return new InetSocketAddress(Integer.parseInt(addressPort));
}
String addressStr = addressPort.substring(0, portPos);
String portStr = addressPort.substring(portPos + 1);
int port = parseInt(portStr);
checkArgument(port > 0 && port < 65536, "Invalid address. Port is not in range (0, 65536) " + addressStr);
InetSocketAddress socketAddress;
if ("*".equals(addressStr)) {
socketAddress = new InetSocketAddress(port);
} else {
try {
InetAddress address = InetAddress.getByName(addressStr);
socketAddress = new InetSocketAddress(address, port);
} catch (UnknownHostException e) {
throw new IllegalArgumentException(e);
}
}
return socketAddress;
}
@Override
public String toString(InetSocketAddress value) {
return value.getAddress().getHostAddress() + ":" + value.getPort();
}
};
}
public static ConfigConverter ofPath() {
return new SimpleConfigConverter() {
@Override
protected Path fromString(String string) {
return Paths.get(string);
}
@Override
protected String toString(Path value) {
return value.toAbsolutePath().normalize().toString();
}
};
}
public static ConfigConverter ofMemSize() {
return new SimpleConfigConverter() {
@Override
public MemSize fromString(String string) {
return MemSize.valueOf(string);
}
@Override
public String toString(MemSize value) {
return value.format();
}
};
}
/**
* @return config converter with bytes in memsize
*/
public static ConfigConverter ofMemSizeAsLong() {
return ofMemSize().transform(MemSize::toLong, MemSize::of);
}
/**
* @return config converter with bytes in memsize
*/
public static ConfigConverter ofMemSizeAsInt() {
return ofMemSize().transform(MemSize::toInt, (Function) MemSize::of);
}
public static ConfigConverter ofInetAddressRange() {
return new SimpleConfigConverter() {
@Override
public InetAddressRange fromString(String string) {
try {
return InetAddressRange.parse(string);
} catch (ParseException e) {
throw new IllegalArgumentException("Can't parse inetAddressRange config", e);
}
}
@Override
public String toString(InetAddressRange value) {
return value.toString();
}
};
}
public static ConfigConverter> ofList(ConfigConverter elementConverter, CharSequence separators) {
return new SimpleConfigConverter>() {
private final Pattern pattern = compile(separators.chars()
.mapToObj(c -> "\\" + ((char) c))
.collect(joining("", "[", "]")));
@Override
public List fromString(String string) {
return pattern.splitAsStream(string)
.map(String::trim)
.filter(s -> !s.isEmpty())
.map(s -> elementConverter.get(Config.ofValue(s)))
.collect(toList());
}
@Override
public String toString(List value) {
return value.stream()
.map(v -> {
Config config = Config.ofValue(elementConverter, v);
if (config.hasChildren()) {
throw new AssertionError("Unexpected child entries: " + config.toMap());
}
return config.getValue();
})
.collect(joining(String.valueOf(separators.charAt(0))));
}
};
}
public static ConfigConverter> ofList(ConfigConverter elementConverter) {
return ofList(elementConverter, ",;");
}
// compound
public static ConfigConverter ofServerSocketSettings() {
return new ComplexConfigConverter(ServerSocketSettings.create(DEFAULT_BACKLOG)) {
@Override
protected ServerSocketSettings provide(Config config, ServerSocketSettings defaultValue) {
return Function.identity()
.andThen(apply(
ServerSocketSettings::withBacklog,
config.get(ofInteger(), "backlog", defaultValue.getBacklog())))
.andThen(applyIfNotNull(
ServerSocketSettings::withReceiveBufferSize,
config.get(ofMemSize(), "receiveBufferSize",
defaultValue.hasReceiveBufferSize() ? defaultValue.getReceiveBufferSize() : null)))
.andThen(applyIfNotNull(
ServerSocketSettings::withReuseAddress,
config.get(ofBoolean(), "reuseAddress",
defaultValue.hasReuseAddress() ? defaultValue.getReuseAddress() : null)))
.apply(ServerSocketSettings.create(DEFAULT_BACKLOG));
}
};
}
public static ConfigConverter ofSocketSettings() {
return new ComplexConfigConverter(SocketSettings.create()) {
@Override
protected SocketSettings provide(Config config, SocketSettings defaultValue) {
return Function.identity()
.andThen(applyIfNotNull(
SocketSettings::withReceiveBufferSize,
config.get(ofMemSize(), "receiveBufferSize",
defaultValue.hasReceiveBufferSize() ? defaultValue.getReceiveBufferSize() : null)))
.andThen(applyIfNotNull(
SocketSettings::withSendBufferSize,
config.get(ofMemSize(), "sendBufferSize",
defaultValue.hasSendBufferSize() ? defaultValue.getSendBufferSize() : null)))
.andThen(applyIfNotNull(
SocketSettings::withReuseAddress,
config.get(ofBoolean(), "reuseAddress",
defaultValue.hasReuseAddress() ? defaultValue.getReuseAddress() : null)))
.andThen(applyIfNotNull(
SocketSettings::withKeepAlive,
config.get(ofBoolean(), "keepAlive",
defaultValue.hasKeepAlive() ? defaultValue.getKeepAlive() : null)))
.andThen(applyIfNotNull(
SocketSettings::withTcpNoDelay,
config.get(ofBoolean(), "tcpNoDelay",
defaultValue.hasTcpNoDelay() ? defaultValue.getTcpNoDelay() : null)))
.andThen(applyIfNotNull(
SocketSettings::withImplReadTimeout,
config.get(ofDuration(), "implReadTimeout",
defaultValue.hasImplReadTimeout() ? defaultValue.getImplReadTimeout() : null)))
.andThen(applyIfNotNull(
SocketSettings::withImplWriteTimeout,
config.get(ofDuration(), "implWriteTimeout",
defaultValue.hasImplWriteTimeout() ? defaultValue.getImplWriteTimeout() : null)))
.andThen(applyIfNotNull(
SocketSettings::withImplReadSize,
config.get(ofMemSize(), "implReadSize",
defaultValue.hasImplReadSize() ? defaultValue.getImplReadSize() : null)))
.andThen(applyIfNotNull(
SocketSettings::withImplWriteSize,
config.get(ofMemSize(), "implWriteSize",
defaultValue.hasImplWriteSize() ? defaultValue.getImplWriteSize() : null)))
.apply(SocketSettings.create());
}
};
}
public static ConfigConverter ofDatagramSocketSettings() {
return new ComplexConfigConverter(DatagramSocketSettings.create()) {
@Override
protected DatagramSocketSettings provide(Config config, DatagramSocketSettings defaultValue) {
return Function.identity()
.andThen(applyIfNotNull(
DatagramSocketSettings::withReceiveBufferSize,
config.get(ofMemSize(), "receiveBufferSize",
defaultValue.hasReceiveBufferSize() ? defaultValue.getReceiveBufferSize() : null)))
.andThen(applyIfNotNull(
DatagramSocketSettings::withSendBufferSize,
config.get(ofMemSize(), "sendBufferSize",
defaultValue.hasSendBufferSize() ? defaultValue.getSendBufferSize() : null)))
.andThen(applyIfNotNull(
DatagramSocketSettings::withReuseAddress,
config.get(ofBoolean(), "reuseAddress",
defaultValue.hasReuseAddress() ? defaultValue.getReuseAddress() : null)))
.andThen(applyIfNotNull(
DatagramSocketSettings::withBroadcast,
config.get(ofBoolean(), "broadcast",
defaultValue.hasBroadcast() ? defaultValue.getBroadcast() : null)))
.apply(DatagramSocketSettings.create());
}
};
}
public static final ConfigConverter> OF_CLASSES = ofList(ofClass());
public static ConfigConverter ofFatalErrorHandler() {
return new ConfigConverter() {
@Override
public FatalErrorHandler get(Config config) {
switch (config.getValue()) {
case "rethrowOnAnyError":
return rethrowOnAnyError();
case "ignoreAllErrors":
return ignoreAllErrors();
case "exitOnAnyError":
return exitOnAnyError();
case "exitOnJvmError":
return exitOnJvmError();
case "rethrowOnMatchedError":
return rethrowOnMatchedError(
config.get(OF_CLASSES, "whitelist", emptyList()),
config.get(OF_CLASSES, "blacklist", emptyList()));
case "exitOnMatchedError":
return exitOnMatchedError(
config.get(OF_CLASSES, "whitelist", emptyList()),
config.get(OF_CLASSES, "blacklist", emptyList()));
default:
throw new IllegalArgumentException("No fatal error handler named " + config.getValue() + " exists!");
}
}
@Override
public FatalErrorHandler get(Config config, FatalErrorHandler defaultValue) {
if (config.isEmpty()) {
return defaultValue;
}
return get(config);
}
};
}
public static ConfigConverter ofEventloopTaskSchedule() {
return new ConfigConverter() {
@Override
public EventloopTaskScheduler.Schedule get(Config config) {
switch (config.get("type")) {
case "immediate":
return EventloopTaskScheduler.Schedule.immediate();
case "delay":
return EventloopTaskScheduler.Schedule.ofDelay(config.get(ofDuration(), "value"));
case "interval":
return EventloopTaskScheduler.Schedule.ofInterval(config.get(ofDuration(), "value"));
case "period":
return EventloopTaskScheduler.Schedule.ofPeriod(config.get(ofDuration(), "value"));
default:
throw new IllegalArgumentException("No eventloop task schedule type named " + config.getValue() + " exists!");
}
}
@Override
public EventloopTaskScheduler.Schedule get(Config config, EventloopTaskScheduler.Schedule defaultValue) {
if (config.isEmpty()) {
return defaultValue;
}
return get(config);
}
};
}
public static ConfigConverter ofRetryPolicy() {
return new ConfigConverter() {
@Override
public RetryPolicy get(Config config) {
if (!config.hasValue() || config.getValue().equals("no")) {
return RetryPolicy.noRetry();
}
RetryPolicy retryPolicy;
switch (config.getValue()) {
case "immediate":
retryPolicy = RetryPolicy.immediateRetry();
break;
case "fixedDelay":
retryPolicy = RetryPolicy.fixedDelay(config.get(ofDuration(), "delay").toMillis());
break;
case "exponentialBackoff":
retryPolicy = RetryPolicy.exponentialBackoff(config.get(ofDuration(), "initialDelay").toMillis(),
config.get(ofDuration(), "maxDelay").toMillis(), config.get(ofDouble(), "exponent", 2.0));
break;
default:
throw new IllegalArgumentException("No retry policy named " + config.getValue() + " exists!");
}
int maxRetryCount = config.get(ofInteger(), "maxRetryCount", Integer.MAX_VALUE);
if (maxRetryCount != Integer.MAX_VALUE) {
retryPolicy = retryPolicy.withMaxTotalRetryCount(maxRetryCount);
}
Duration max = Duration.ofSeconds(Long.MAX_VALUE);
Duration maxRetryTimeout = config.get(ofDuration(), "maxRetryTimeout", max);
if (!maxRetryTimeout.equals(max)) {
retryPolicy = retryPolicy.withMaxTotalRetryTimeout(maxRetryTimeout);
}
return retryPolicy;
}
@Override
public RetryPolicy get(Config config, RetryPolicy defaultValue) {
if (config.isEmpty()) {
return defaultValue;
}
return get(config);
}
};
}
public static ConfigConverter ofThrottlingController() {
return new ComplexConfigConverter(ThrottlingController.create()) {
@Override
protected ThrottlingController provide(Config config, ThrottlingController defaultValue) {
return ThrottlingController.create()
.withTargetTime(config.get(ofDuration(), "targetTime", defaultValue.getTargetTimeMillis()))
.withGcTime(config.get(ofDuration(), "gcTime", defaultValue.getGcTimeMillis()))
.withSmoothingWindow(config.get(ofDuration(), "smoothingWindow", defaultValue.getSmoothingWindow()))
.withThrottlingDecrease(config.get(ofDouble(), "throttlingDecrease", defaultValue.getThrottlingDecrease()))
.withInitialKeysPerSecond(config.get(ofDouble(), "initialKeysPerSecond", INITIAL_KEYS_PER_SECOND))
.withInitialThrottling(config.get(ofDouble(), "initialThrottling", INITIAL_THROTTLING));
}
};
}
public static ConfigConverter ofThreadFactory() {
return new ComplexConfigConverter(SimpleThreadFactory.create()) {
@Override
protected SimpleThreadFactory provide(Config config, SimpleThreadFactory defaultValue) {
SimpleThreadFactory result = SimpleThreadFactory.create();
String threadGroupName = config.get(ofNullableString(), "threadGroup", Utils.transform(defaultValue.getThreadGroup(), ThreadGroup::getName));
if (threadGroupName != null) {
result = result.withThreadGroup(new ThreadGroup(threadGroupName));
}
return result
.withName(config.get(ofNullableString(), "name", defaultValue.getName()))
.withPriority(config.get(ofInteger(), "priority", defaultValue.getPriority()))
.withDaemon(config.get(ofBoolean(), "daemon", defaultValue.isDaemon()));
}
};
}
public static ExecutorService getExecutor(Config config) {
int corePoolSize = config.get(ofInteger().withConstraint(x -> x >= 0), "corePoolSize", 0);
int maxPoolSize = config.get(ofInteger().withConstraint(x -> x == 0 || x >= corePoolSize), "maxPoolSize", 0);
int keepAlive = config.get(ofInteger().withConstraint(x -> x >= 0), "keepAliveSeconds", 60);
return new ThreadPoolExecutor(
corePoolSize,
maxPoolSize == 0 ? Integer.MAX_VALUE : maxPoolSize,
keepAlive,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>());
}
public static ConfigConverter ofExecutor() {
return new ConfigConverter() {
@Override
public ExecutorService get(Config config) {
return getExecutor(config);
}
@Override
public ExecutorService get(Config config, ExecutorService defaultValue) {
throw new UnsupportedOperationException();
}
};
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy