com.github.lontime.extredisson.configuration.OptionResolver Maven / Gradle / Ivy
The newest version!
package com.github.lontime.extredisson.configuration;
import java.net.URI;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import com.github.lontime.base.commonj.utils.CollectionHelper;
import com.github.lontime.base.commonj.utils.NetHelper;
import com.github.lontime.base.commonj.utils.StringHelper;
import com.github.lontime.base.commonj.utils.SupplierHelper;
import com.github.lontime.base.serial.model.Header;
import com.github.lontime.extconfig.ConfigHelper;
import com.github.lontime.extconfig.WrapperConfig;
import com.github.lontime.extredisson.common.ClientKind;
import com.github.lontime.extredisson.common.CodecKind;
import com.github.lontime.extredisson.common.InternalRPCUtils;
import com.github.lontime.extredisson.common.ListenerKind;
import com.github.lontime.extredisson.common.LoadBalancerPolicy;
import com.github.lontime.extredisson.common.RedisKeys;
import com.github.lontime.extredisson.common.WatchKind;
import com.github.lontime.shaded.com.google.common.base.Splitter;
import com.github.lontime.shaded.io.helidon.config.Config;
import com.github.lontime.shaded.org.redisson.api.StreamMessageId;
import com.github.lontime.shaded.org.redisson.config.ReadMode;
import com.github.lontime.shaded.org.redisson.config.SslProvider;
import com.github.lontime.shaded.org.redisson.config.SubscriptionMode;
import com.github.lontime.shaded.org.redisson.config.TransportMode;
import com.github.lontime.shaded.org.redisson.connection.balancer.LoadBalancer;
import com.github.lontime.shaded.org.redisson.connection.balancer.RandomLoadBalancer;
import com.github.lontime.shaded.org.redisson.connection.balancer.RoundRobinLoadBalancer;
import com.github.lontime.shaded.org.redisson.connection.balancer.WeightedRoundRobinBalancer;
import static com.github.lontime.extredisson.common.Constants.CONSUMER_DEFAULT_GROUP;
import static com.github.lontime.extredisson.common.Constants.SERVICE_REPLYS;
/**
* Redisson Option Resolver.
*
* @author lontime
* @since 1.0
*/
public class OptionResolver {
private static final String NAME = "redisson";
//------------------singleton------------------
/**
* supplier.
*/
private static Supplier supplier = SupplierHelper.memoize(OptionResolver::new);
public static OptionResolver getInstance() {
return supplier.get();
}
//------------------singleton------------------
private final Options redissonOptions;
public OptionResolver() {
this.redissonOptions = ConfigHelper.resolve(NAME).as(new Mapper()).orElse(new Options());
}
public RedisKeys getProjectName() {
return redissonOptions.getProjectName();
}
public String ip() {
return redissonOptions.getIp();
}
public Duration getWaitPollTimeout() {
return redissonOptions.getWaitPollTimeout();
}
public List getConnections() {
final List connections = redissonOptions.getConnections();
return CollectionHelper.isEmpty(connections) ? Collections.emptyList() : connections;
}
public ProducerOption getProducer(String name) {
if (StringHelper.isNotEmpty(name)) {
final List producers = redissonOptions.getProducers();
for (ProducerOption producer : producers) {
if (producer.getName().equals(name)) {
return producer;
}
}
}
return ProducerOption.topic(name);
}
public NodeOption getNodeOption() {
return redissonOptions.getNode();
}
public ConnectionOption getConnection(String name) {
final List connections = getConnections();
if (StringHelper.isEmpty(name) || CollectionHelper.isEmpty(connections)) {
return null;
}
return connections.stream().filter(s -> name.equals(s.getName())).findFirst().orElse(null);
}
public List getConsumers() {
final List consumers = redissonOptions.getConsumers();
final List services = redissonOptions.getServices();
final List all = new ArrayList<>();
if (CollectionHelper.isNotEmpty(consumers)) {
all.addAll(consumers);
}
if (CollectionHelper.isNotEmpty(services)) {
all.addAll(services);
}
return all;
}
public List getStreamNames() {
return getConsumers().stream().map(ConsumerOption::getTopic).collect(Collectors.toList());
}
public RegistryOption registry() {
return Optional.ofNullable(redissonOptions.getRegistry()).orElse(new RegistryOption());
}
public WatchOption getWatchOption() {
return redissonOptions.getWatch();
}
static class Mapper implements Function {
@Override
public Options apply(Config config) {
final Options options = new Options();
final WrapperConfig wrapperConfig = new WrapperConfig(config);
options.setIp(wrapperConfig.getAsString("ip").orElseGet(NetHelper::getLocalHost));
wrapperConfig.getAsString("project").map(RedisKeys::create).ifPresent(options::setProjectName);
options.setNode(config.get("node").as(new NodeMapper()).orElseGet(NodeOption::create));
config.get("connections").asList(new ConnectionMapper()).ifPresent(options::setConnections);
config.get("producers").asList(new ProducerMapper()).ifPresent(options::setProducers);
config.get("consumers").asList(new ConsumerMapper()).ifPresent(options::setConsumers);
config.get("services").asList(new ServiceMapper()).ifPresent(options::setServices);
config.get("watch").as(new WatchMapper()).ifPresent(options::setWatch);
config.get("registry").as(new RegistryMapper()).ifPresent(options::setRegistry);
wrapperConfig.getAsDuration("waitPollTimeout").ifPresent(options::setWaitPollTimeout);
return options;
}
}
static class NodeMapper implements Function {
@Override
public NodeOption apply(Config config) {
final WrapperConfig wrapperConfig = new WrapperConfig(config);
final NodeOption option = wrapperConfig.getAsString("id")
.map(NodeOption::create).orElseGet(NodeOption::create);
wrapperConfig.getAsDuration("period").ifPresent(option::setPeriod);
wrapperConfig.getAsDuration("ttl").ifPresent(option::setTtl);
wrapperConfig.getAsString("namespace").ifPresent(option::setNamespace);
return option;
}
}
static class ProducerMapper implements Function {
@Override
public ProducerOption apply(Config config) {
final String name = config.get("name").asString().orElse(config.name());
final ProducerOption option = new ProducerOption();
option.setName(name);
option.setTopic(config.get("topic").asString().orElse(name));
config.get("timeout").asString().map(Duration::parse).ifPresent(option::setTimeout);
config.get("headers").detach().asMap().map(this::headers).ifPresent(option::setHeaders);
config.get("tags").asString()
.map(s -> Splitter.on(",").trimResults().omitEmptyStrings().splitToList(s))
.ifPresent(option::setTags);
config.get("ref").asBoolean().ifPresent(option::setRef);
config.get("enableReply").asBoolean().ifPresent(option::setEnableReply);
config.get("maxRecheck").asInt().ifPresent(option::setMaxRecheck);
config.get("page").asInt().ifPresent(option::setPage);
return option;
}
public List headers(Map map) {
final List headers = new ArrayList<>(map.size());
for (Map.Entry entry : map.entrySet()) {
headers.add(Header.from(entry.getKey(), entry.getValue()));
}
return headers;
}
}
static class RegistryMapper implements Function {
@Override
public RegistryOption apply(Config config) {
final RegistryOption options = new RegistryOption();
config.get("name").asString().ifPresent(options::setName);
config.get("keepAlive").asString().map(Duration::parse).ifPresent(options::setKeepAlive);
return options;
}
}
static class WatchMapper implements Function {
@Override
public WatchOption apply(Config config) {
final WatchOption option = new WatchOption();
config.get("enabled").asBoolean().ifPresent(option::setEnabled);
config.get("interval").asString().map(Duration::parse).ifPresent(option::setInterval);
config.get("warmup").asString().map(Duration::parse).ifPresent(option::setWarmup);
config.get("enableStream").asBoolean().ifPresent(option::setEnableStream);
config.get("specs").asList(this::spec).ifPresent(option::setSpecs);
config.get("enableServiceReply").asBoolean().ifPresent(option::setEnableServiceReply);
config.get("serviceReply").as(this::spec).map(s -> {
s.setName(SERVICE_REPLYS);
s.setKind(WatchKind.REPLY);
return s;
}).ifPresent(option::setServiceReply);
return option;
}
private WatchOption.Spec spec(Config config) {
WatchOption.Spec specOption = new WatchOption.Spec();
specOption.setName(config.get("name").asString().orElse(config.name()));
config.get("kind").asString().map(ConfigHelper::formatEnumName).map(WatchKind::valueOf)
.ifPresent(specOption::setKind);
config.get("maxLen").asInt().ifPresent(specOption::setMaxLen);
config.get("maxLenRate").asDouble().ifPresent(specOption::setMaxLenRate);
config.get("timeToLive").asString().map(Duration::parse).ifPresent(specOption::setTimeToLive);
config.get("lockWaitTime").asString().map(Duration::parse).ifPresent(specOption::setLockWaitTime);
config.get("lockLeaseTime").asString().map(Duration::parse).ifPresent(specOption::setLockLeaseTime);
config.get("batchSize").asInt().ifPresent(specOption::setBatchSize);
return specOption;
}
}
static class ServiceMapper implements Function {
@Override
public ConsumerOption apply(Config config) {
final CommonConsumerMapper mapper = new CommonConsumerMapper();
final ConsumerOption option = mapper.apply(config);
config.get("service").asString().ifPresent(option::setTopic);
option.setKind(ListenerKind.SERVICE);
option.setMessageId(StreamMessageId.NEWEST);
option.setGroupNoAck(Boolean.TRUE);
return option;
}
}
static class ConsumerMapper implements Function {
@Override
public ConsumerOption apply(Config config) {
final CommonConsumerMapper mapper = new CommonConsumerMapper();
final ConsumerOption option = mapper.apply(config);
option.setKind(ListenerKind.STREAM);
return option;
}
}
static class CommonConsumerMapper implements Function {
@Override
public ConsumerOption apply(Config config) {
final WrapperConfig wrapperConfig = new WrapperConfig(config);
final String name = config.name();
final ConsumerOption option = new ConsumerOption();
config.get("tag").asString().ifPresent(option::setTag);
option.setName(config.get("name").asString().orElse(name));
option.setGroupName(config.get("groupName").asString().orElse(CONSUMER_DEFAULT_GROUP));
wrapperConfig.getAsEnum("kind", ListenerKind::valueOf).ifPresent(option::setKind);
// config.get("kind").asString().map(String::toUpperCase).map(ListenerKind::valueOf).ifPresent(option::setKind);
config.get("ref").asBoolean().ifPresent(option::setRef);
option.setTopic(config.get("topic").asString().orElse(name));
config.get("next").asString().ifPresent(option::setNext);
config.get("messageId").asString().map(this::streamMessageId).ifPresent(option::setMessageId);
config.get("batchSize").asInt().ifPresent(option::setBatchSize);
config.get("initLatestSize").asInt().ifPresent(option::setInitLatestSize);
wrapperConfig.getAsDuration("timeout").ifPresent(option::setTimeout);
option.setListener(config.get("listener").asString().orElse(name));
wrapperConfig.getAsDuration("interval").ifPresent(option::setInterval);
wrapperConfig.getAsDuration("warmup").ifPresent(option::setWarmup);
// config.get("groupName").asString().ifPresent(option::setGroupName);
config.get("groupNoAck").asBoolean().ifPresent(option::setGroupNoAck);
config.get("lazyListener").asBoolean().ifPresent(option::setLazyListener);
wrapperConfig.getAsBoolean("enableClean").ifPresent(option::setEnableClean);
wrapperConfig.getAsDuration("heartbeatInterval").ifPresent(option::setHeartbeatInterval);
wrapperConfig.getAsDuration("localCleanInterval").ifPresent(option::setLocalCleanInterval);
wrapperConfig.getAsDuration("cleanInterval").ifPresent(option::setCleanInterval);
config.get("broadcast").asBoolean().ifPresent(option::setBroadcast);
config.get("disableGroup").asBoolean().ifPresent(option::setDisableGroup);
config.get("maxLen").asInt().ifPresent(option::setMaxLen);
config.get("maxLenRate").asDouble().ifPresent(option::setMaxLenRate);
return option;
}
private StreamMessageId streamMessageId(String m) {
final char c = m.charAt(0);
switch (c) {
case '>':
return StreamMessageId.NEVER_DELIVERED;
case '$':
return StreamMessageId.NEWEST;
case '0':
return StreamMessageId.ALL;
default:
return InternalRPCUtils.parseMessageId(m);
}
}
}
static class ConnectionMapper implements Function {
@Override
public ConnectionOption apply(Config config) {
final ConnectionOption options = new ConnectionOption();
options.setName(config.name());
config.get("kind").asString()
.map(String::toUpperCase)
.map(s -> ClientKind.valueOf(s))
.ifPresent(options::setKind);
config.get("database").asInt().ifPresent(options::setDatabase);
config.get("username").asString().ifPresent(options::setUsername);
config.get("password").asString().ifPresent(options::setPassword);
config.get("clientName").asString().ifPresent(options::setClientName);
config.get("codec").asString().map(String::toUpperCase)
.map(s -> CodecKind.valueOf(s)).ifPresent(options::setCodec);
config.get("threads").asInt().ifPresent(options::setThreads);
config.get("nettyThreads").asInt().ifPresent(options::setNettyThreads);
config.get("executor").asString().ifPresent(options::setExecutor);
config.get("transportMode").asString().map(String::toUpperCase)
.map(s -> TransportMode.valueOf(s)).ifPresent(options::setTransportMode);
config.get("lockWatchdogTimeout").asInt().ifPresent(options::setLockWatchdogTimeout);
config.get("keepPubSubOrder").asBoolean().ifPresent(options::setKeepPubSubOrder);
config.get("performanceMode").asString().ifPresent(options::setPerformanceMode);
config.get("sslEnableEndpointIdentification").asBoolean().ifPresent(options::setSslEnableEndpointIdentification);
config.get("sslProvider").asString().map(String::toUpperCase).map(s -> SslProvider.valueOf(s))
.ifPresent(options::setSslProvider);
config.get("sslTruststore").asList(String.class).ifPresent(options::setSslProtocols);
config.get("sslTruststore").asString().map(s -> {
try {
return URI.create(s).toURL();
} catch (Exception e) {
return null;
}
}).ifPresent(options::setSslTruststore);
config.get("sslTruststorePassword").asString().ifPresent(options::setSslTruststorePassword);
config.get("sslKeystore").asString().map(s -> {
try {
return URI.create(s).toURL();
} catch (Exception e) {
return null;
}
}).ifPresent(options::setSslKeystore);
config.get("sslKeystorePassword").asString().ifPresent(options::setSslKeystorePassword);
config.get("dnsMonitoringInterval").asInt().ifPresent(options::setDnsMonitoringInterval);
config.get("pingConnectionInterval").asInt().ifPresent(options::setPingConnectionInterval);
config.get("keepAlive").asBoolean().ifPresent(options::setKeepAlive);
config.get("tcpNoDelay").asBoolean().ifPresent(options::setTcpNoDelay);
config.get("idleConnectionTimeout").asInt().ifPresent(options::setIdleConnectionTimeout);
config.get("connectTimeout").asInt().ifPresent(options::setConnectTimeout);
config.get("timeout").asInt().ifPresent(options::setTimeout);
config.get("retryAttempts").asInt().ifPresent(options::setRetryAttempts);
config.get("retryInterval").asInt().ifPresent(options::setRetryInterval);
config.get("subscriptionsPerConnection").asInt().ifPresent(options::setSubscriptionsPerConnection);
config.get("subscriptionConnectionMinimumIdleSize").asInt().ifPresent(options::setSubscriptionConnectionMinimumIdleSize);
config.get("subscriptionConnectionPoolSize").asInt().ifPresent(options::setSubscriptionConnectionPoolSize);
config.get("readMode").asString().map(String::toUpperCase).map(s -> ReadMode.valueOf(s)).ifPresent(options::setReadMode);
config.get("subscriptionMode").asString().map(String::toUpperCase).map(s -> SubscriptionMode.valueOf(s)).ifPresent(options::setSubscriptionMode);
config.get("loadBalancer").asString()
.map(String::toUpperCase)
.map(s -> LoadBalancerPolicy.valueOf(s))
.map(s -> this.balancer(s, config.get("weights")))
.ifPresent(options::setLoadBalancer);
config.get("failedSlaveReconnectionInterval").asInt().ifPresent(options::setFailedSlaveReconnectionInterval);
config.get("failedSlaveCheckInterval").asInt().ifPresent(options::setFailedSlaveCheckInterval);
config.get("slaveConnectionMinimumIdleSize").asInt().ifPresent(options::setSlaveConnectionMinimumIdleSize);
config.get("slaveConnectionPoolSize").asInt().ifPresent(options::setSlaveConnectionPoolSize);
config.get("masterConnectionMinimumIdleSize").asInt().ifPresent(options::setMasterConnectionMinimumIdleSize);
config.get("masterConnectionPoolSize").asInt().ifPresent(options::setMasterConnectionPoolSize);
//cluster
config.get("cluster").asNode().map(this::cluster).ifPresent(options::setCluster);
//sentinel
config.get("sentinel").asNode().map(this::sentinel).ifPresent(options::setSentinel);
//MasterSlave
config.get("masterSlave").asNode().map(this::masterSlave).ifPresent(options::setMasterSlave);
//single
// config.get("single").asNode().map(this::single).ifPresent(options::setSingle);
config.get("address").asString().ifPresent(options::setAddress);
config.get("connectionMinimumIdleSize").asInt().ifPresent(options::setConnectionMinimumIdleSize);
config.get("connectionPoolSize").asInt().ifPresent(options::setConnectionPoolSize);
return options;
}
private ConnectionOption.MasterSlave masterSlave(Config config) {
final ConnectionOption.MasterSlave masterSlave = new ConnectionOption.MasterSlave();
config.get("slaveAddress").asList(String.class).map(s -> new HashSet<>(s)).ifPresent(masterSlave::setSlaveAddress);
config.get("masterAddress").asString().ifPresent(masterSlave::setMasterAddress);
return masterSlave;
}
private ConnectionOption.Sentinel sentinel(Config config) {
final ConnectionOption.Sentinel sentinel = new ConnectionOption.Sentinel();
config.get("sentinelAddress").asList(String.class).ifPresent(sentinel::setSentinelAddress);
config.get("masterName").asString().ifPresent(sentinel::setMasterName);
config.get("sentinelPassword").asString().ifPresent(sentinel::setSentinelPassword);
config.get("scanInterval").asInt().ifPresent(sentinel::setScanInterval);
config.get("checkSentinelsList").asBoolean().ifPresent(sentinel::setCheckSentinelsList);
config.get("checkSlaveStatusWithSyncing").asBoolean().ifPresent(sentinel::setCheckSlaveStatusWithSyncing);
config.get("sentinelsDiscovery").asBoolean().ifPresent(sentinel::setSentinelsDiscovery);
return sentinel;
}
private ConnectionOption.Cluster cluster(Config config) {
final ConnectionOption.Cluster cluster = new ConnectionOption.Cluster();
config.get("nodeAddresses").asList(String.class).ifPresent(cluster::setNodeAddresses);
config.get("scanInterval").asInt().ifPresent(cluster::setScanInterval);
config.get("slots").asInt().ifPresent(cluster::setSlots);
config.get("checkSlotsCoverage").asBoolean().ifPresent(cluster::setCheckSlotsCoverage);
return cluster;
}
private LoadBalancer balancer(LoadBalancerPolicy policy, Config weightConfig) {
if (policy == LoadBalancerPolicy.ROUND_ROBIN) {
return new RoundRobinLoadBalancer();
}
if (policy == LoadBalancerPolicy.RANDOM) {
return new RandomLoadBalancer();
}
if (policy == LoadBalancerPolicy.WEIGHTED_ROUND_ROBIN) {
final Map hostMap = weightConfig.get("uris").detach().asMap().orElse(null);
if (CollectionHelper.isEmpty(hostMap)) {
return null;
}
final Integer defaultWeight = weightConfig.get("defaultWeight").asInt().orElse(100 / hostMap.size());
final Map weights = new HashMap<>();
for (Map.Entry entry : hostMap.entrySet()) {
weights.put(Config.Key.unescapeName(entry.getKey()),
Integer.valueOf(entry.getValue()));
}
return new WeightedRoundRobinBalancer(weights, defaultWeight);
}
return null;
}
}
}