ConnectionConfig.java
/*
* SPDX-FileCopyrightText: 2023-2025 Lucimber UG
* SPDX-License-Identifier: Apache-2.0
*/
package com.lucimber.dbus.connection;
import java.time.Duration;
import java.util.Objects;
/**
* Configuration class for D-Bus connections containing timeout and other connection settings. This
* class uses a builder pattern to allow for flexible configuration.
*/
public final class ConnectionConfig {
private static final Duration DEFAULT_METHOD_CALL_TIMEOUT = Duration.ofSeconds(30);
private static final Duration DEFAULT_CONNECT_TIMEOUT = Duration.ofSeconds(10);
private static final Duration DEFAULT_READ_TIMEOUT = Duration.ofSeconds(60);
private static final Duration DEFAULT_WRITE_TIMEOUT = Duration.ofSeconds(10);
private static final Duration DEFAULT_HEALTH_CHECK_INTERVAL = Duration.ofSeconds(30);
private static final Duration DEFAULT_HEALTH_CHECK_TIMEOUT = Duration.ofSeconds(5);
private static final Duration DEFAULT_RECONNECT_INITIAL_DELAY = Duration.ofSeconds(1);
private static final Duration DEFAULT_RECONNECT_MAX_DELAY = Duration.ofMinutes(5);
private static final int DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;
private static final Duration DEFAULT_CLOSE_TIMEOUT = Duration.ofSeconds(5);
private final Duration methodCallTimeout;
private final Duration connectTimeout;
private final Duration readTimeout;
private final Duration writeTimeout;
private final boolean healthCheckEnabled;
private final Duration healthCheckInterval;
private final Duration healthCheckTimeout;
private final boolean autoReconnectEnabled;
private final Duration reconnectInitialDelay;
private final Duration reconnectMaxDelay;
private final double reconnectBackoffMultiplier;
private final int maxReconnectAttempts;
private final Duration closeTimeout;
private ConnectionConfig(Builder builder) {
this.methodCallTimeout = builder.methodCallTimeout;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.healthCheckEnabled = builder.healthCheckEnabled;
this.healthCheckInterval = builder.healthCheckInterval;
this.healthCheckTimeout = builder.healthCheckTimeout;
this.autoReconnectEnabled = builder.autoReconnectEnabled;
this.reconnectInitialDelay = builder.reconnectInitialDelay;
this.reconnectMaxDelay = builder.reconnectMaxDelay;
this.reconnectBackoffMultiplier = builder.reconnectBackoffMultiplier;
this.maxReconnectAttempts = builder.maxReconnectAttempts;
this.closeTimeout = builder.closeTimeout;
}
/**
* Creates a new builder with default timeout values.
*
* @return A new builder instance
*/
public static Builder builder() {
return new Builder();
}
/**
* Creates a default configuration with all default timeout values.
*
* @return A default configuration instance
*/
public static ConnectionConfig defaultConfig() {
return builder().build();
}
/**
* Gets the timeout for method call responses.
*
* @return The method call timeout duration
*/
public Duration getMethodCallTimeout() {
return methodCallTimeout;
}
/**
* Gets the timeout for establishing connections.
*
* @return The connection timeout duration
*/
public Duration getConnectTimeout() {
return connectTimeout;
}
/**
* Gets the timeout for read operations.
*
* @return The read timeout duration
*/
public Duration getReadTimeout() {
return readTimeout;
}
/**
* Gets the timeout for write operations.
*
* @return The write timeout duration
*/
public Duration getWriteTimeout() {
return writeTimeout;
}
/**
* Gets the method call timeout in milliseconds for compatibility with existing code.
*
* @return The method call timeout in milliseconds
*/
public long getMethodCallTimeoutMs() {
return methodCallTimeout.toMillis();
}
/**
* Gets the connection timeout in milliseconds for compatibility with existing code.
*
* @return The connection timeout in milliseconds
*/
public long getConnectTimeoutMs() {
return connectTimeout.toMillis();
}
/**
* Gets the read timeout in milliseconds for compatibility with existing code.
*
* @return The read timeout in milliseconds
*/
public long getReadTimeoutMs() {
return readTimeout.toMillis();
}
/**
* Gets the write timeout in milliseconds for compatibility with existing code.
*
* @return The write timeout in milliseconds
*/
public long getWriteTimeoutMs() {
return writeTimeout.toMillis();
}
/**
* Gets whether health check monitoring is enabled.
*
* @return true if health checks are enabled
*/
public boolean isHealthCheckEnabled() {
return healthCheckEnabled;
}
/**
* Gets the interval between health checks.
*
* @return The health check interval duration
*/
public Duration getHealthCheckInterval() {
return healthCheckInterval;
}
/**
* Gets the timeout for individual health checks.
*
* @return The health check timeout duration
*/
public Duration getHealthCheckTimeout() {
return healthCheckTimeout;
}
/**
* Gets whether automatic reconnection is enabled.
*
* @return true if auto-reconnect is enabled
*/
public boolean isAutoReconnectEnabled() {
return autoReconnectEnabled;
}
/**
* Gets the initial delay before the first reconnection attempt.
*
* @return The initial reconnection delay duration
*/
public Duration getReconnectInitialDelay() {
return reconnectInitialDelay;
}
/**
* Gets the maximum delay between reconnection attempts.
*
* @return The maximum reconnection delay duration
*/
public Duration getReconnectMaxDelay() {
return reconnectMaxDelay;
}
/**
* Gets the backoff multiplier for reconnection delays.
*
* @return The backoff multiplier
*/
public double getReconnectBackoffMultiplier() {
return reconnectBackoffMultiplier;
}
/**
* Gets the maximum number of reconnection attempts.
*
* @return The maximum reconnection attempts
*/
public int getMaxReconnectAttempts() {
return maxReconnectAttempts;
}
/**
* Gets the timeout for connection close operations.
*
* @return The close timeout duration
*/
public Duration getCloseTimeout() {
return closeTimeout;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ConnectionConfig that = (ConnectionConfig) o;
return healthCheckEnabled == that.healthCheckEnabled
&& autoReconnectEnabled == that.autoReconnectEnabled
&& Double.compare(that.reconnectBackoffMultiplier, reconnectBackoffMultiplier) == 0
&& maxReconnectAttempts == that.maxReconnectAttempts
&& Objects.equals(methodCallTimeout, that.methodCallTimeout)
&& Objects.equals(connectTimeout, that.connectTimeout)
&& Objects.equals(readTimeout, that.readTimeout)
&& Objects.equals(writeTimeout, that.writeTimeout)
&& Objects.equals(healthCheckInterval, that.healthCheckInterval)
&& Objects.equals(healthCheckTimeout, that.healthCheckTimeout)
&& Objects.equals(reconnectInitialDelay, that.reconnectInitialDelay)
&& Objects.equals(reconnectMaxDelay, that.reconnectMaxDelay)
&& Objects.equals(closeTimeout, that.closeTimeout);
}
@Override
public int hashCode() {
return Objects.hash(
methodCallTimeout,
connectTimeout,
readTimeout,
writeTimeout,
healthCheckEnabled,
healthCheckInterval,
healthCheckTimeout,
autoReconnectEnabled,
reconnectInitialDelay,
reconnectMaxDelay,
reconnectBackoffMultiplier,
maxReconnectAttempts,
closeTimeout);
}
@Override
public String toString() {
return "ConnectionConfig{"
+ "methodCallTimeout="
+ methodCallTimeout
+ ", connectTimeout="
+ connectTimeout
+ ", readTimeout="
+ readTimeout
+ ", writeTimeout="
+ writeTimeout
+ ", healthCheckEnabled="
+ healthCheckEnabled
+ ", healthCheckInterval="
+ healthCheckInterval
+ ", healthCheckTimeout="
+ healthCheckTimeout
+ ", autoReconnectEnabled="
+ autoReconnectEnabled
+ ", reconnectInitialDelay="
+ reconnectInitialDelay
+ ", reconnectMaxDelay="
+ reconnectMaxDelay
+ ", reconnectBackoffMultiplier="
+ reconnectBackoffMultiplier
+ ", maxReconnectAttempts="
+ maxReconnectAttempts
+ ", closeTimeout="
+ closeTimeout
+ '}';
}
/** Builder class for creating ConnectionConfig instances. */
public static final class Builder {
private Duration methodCallTimeout = DEFAULT_METHOD_CALL_TIMEOUT;
private Duration connectTimeout = DEFAULT_CONNECT_TIMEOUT;
private Duration readTimeout = DEFAULT_READ_TIMEOUT;
private Duration writeTimeout = DEFAULT_WRITE_TIMEOUT;
private boolean healthCheckEnabled = true;
private Duration healthCheckInterval = DEFAULT_HEALTH_CHECK_INTERVAL;
private Duration healthCheckTimeout = DEFAULT_HEALTH_CHECK_TIMEOUT;
private boolean autoReconnectEnabled = true;
private Duration reconnectInitialDelay = DEFAULT_RECONNECT_INITIAL_DELAY;
private Duration reconnectMaxDelay = DEFAULT_RECONNECT_MAX_DELAY;
private double reconnectBackoffMultiplier = 2.0;
private int maxReconnectAttempts = DEFAULT_MAX_RECONNECT_ATTEMPTS;
private Duration closeTimeout = DEFAULT_CLOSE_TIMEOUT;
private Builder() {}
/**
* Sets the timeout for method call responses.
*
* @param timeout The timeout duration (must be positive)
* @return This builder instance
* @throws IllegalArgumentException if timeout is null or not positive
*/
public Builder withMethodCallTimeout(Duration timeout) {
Objects.requireNonNull(timeout, "Method call timeout cannot be null");
if (timeout.isNegative() || timeout.isZero()) {
throw new IllegalArgumentException("Method call timeout must be positive");
}
this.methodCallTimeout = timeout;
return this;
}
/**
* Sets the timeout for establishing connections.
*
* @param timeout The timeout duration (must be positive)
* @return This builder instance
* @throws IllegalArgumentException if timeout is null or not positive
*/
public Builder withConnectTimeout(Duration timeout) {
Objects.requireNonNull(timeout, "Connect timeout cannot be null");
if (timeout.isNegative() || timeout.isZero()) {
throw new IllegalArgumentException("Connect timeout must be positive");
}
this.connectTimeout = timeout;
return this;
}
/**
* Sets the timeout for read operations.
*
* @param timeout The timeout duration (must be positive)
* @return This builder instance
* @throws IllegalArgumentException if timeout is null or not positive
*/
public Builder withReadTimeout(Duration timeout) {
Objects.requireNonNull(timeout, "Read timeout cannot be null");
if (timeout.isNegative() || timeout.isZero()) {
throw new IllegalArgumentException("Read timeout must be positive");
}
this.readTimeout = timeout;
return this;
}
/**
* Sets the timeout for write operations.
*
* @param timeout The timeout duration (must be positive)
* @return This builder instance
* @throws IllegalArgumentException if timeout is null or not positive
*/
public Builder withWriteTimeout(Duration timeout) {
Objects.requireNonNull(timeout, "Write timeout cannot be null");
if (timeout.isNegative() || timeout.isZero()) {
throw new IllegalArgumentException("Write timeout must be positive");
}
this.writeTimeout = timeout;
return this;
}
/**
* Sets whether health check monitoring is enabled.
*
* @param enabled true to enable health checks
* @return This builder instance
*/
public Builder withHealthCheckEnabled(boolean enabled) {
this.healthCheckEnabled = enabled;
return this;
}
/**
* Sets the interval between health checks.
*
* @param interval The health check interval (must be positive)
* @return This builder instance
* @throws IllegalArgumentException if interval is null or not positive
*/
public Builder withHealthCheckInterval(Duration interval) {
Objects.requireNonNull(interval, "Health check interval cannot be null");
if (interval.isNegative() || interval.isZero()) {
throw new IllegalArgumentException("Health check interval must be positive");
}
this.healthCheckInterval = interval;
return this;
}
/**
* Sets the timeout for individual health checks.
*
* @param timeout The health check timeout (must be positive)
* @return This builder instance
* @throws IllegalArgumentException if timeout is null or not positive
*/
public Builder withHealthCheckTimeout(Duration timeout) {
Objects.requireNonNull(timeout, "Health check timeout cannot be null");
if (timeout.isNegative() || timeout.isZero()) {
throw new IllegalArgumentException("Health check timeout must be positive");
}
this.healthCheckTimeout = timeout;
return this;
}
/**
* Sets whether automatic reconnection is enabled.
*
* @param enabled true to enable auto-reconnect
* @return This builder instance
*/
public Builder withAutoReconnectEnabled(boolean enabled) {
this.autoReconnectEnabled = enabled;
return this;
}
/**
* Sets the initial delay before the first reconnection attempt.
*
* @param delay The initial reconnection delay (must be positive)
* @return This builder instance
* @throws IllegalArgumentException if delay is null or not positive
*/
public Builder withReconnectInitialDelay(Duration delay) {
Objects.requireNonNull(delay, "Reconnect initial delay cannot be null");
if (delay.isNegative() || delay.isZero()) {
throw new IllegalArgumentException("Reconnect initial delay must be positive");
}
this.reconnectInitialDelay = delay;
return this;
}
/**
* Sets the maximum delay between reconnection attempts.
*
* @param delay The maximum reconnection delay (must be positive)
* @return This builder instance
* @throws IllegalArgumentException if delay is null or not positive
*/
public Builder withReconnectMaxDelay(Duration delay) {
Objects.requireNonNull(delay, "Reconnect max delay cannot be null");
if (delay.isNegative() || delay.isZero()) {
throw new IllegalArgumentException("Reconnect max delay must be positive");
}
this.reconnectMaxDelay = delay;
return this;
}
/**
* Sets the backoff multiplier for reconnection delays.
*
* @param multiplier The backoff multiplier (must be >= 1.0)
* @return This builder instance
* @throws IllegalArgumentException if multiplier is less than 1.0
*/
public Builder withReconnectBackoffMultiplier(double multiplier) {
if (multiplier < 1.0) {
throw new IllegalArgumentException("Reconnect backoff multiplier must be >= 1.0");
}
this.reconnectBackoffMultiplier = multiplier;
return this;
}
/**
* Sets the maximum number of reconnection attempts.
*
* @param attempts The maximum reconnection attempts (must be >= 0, 0 means unlimited)
* @return This builder instance
* @throws IllegalArgumentException if attempts is negative
*/
public Builder withMaxReconnectAttempts(int attempts) {
if (attempts < 0) {
throw new IllegalArgumentException("Max reconnect attempts must be >= 0");
}
this.maxReconnectAttempts = attempts;
return this;
}
/**
* Sets the timeout for connection close operations.
*
* @param timeout The close timeout duration (must be positive)
* @return This builder instance
* @throws IllegalArgumentException if timeout is null or not positive
*/
public Builder withCloseTimeout(Duration timeout) {
Objects.requireNonNull(timeout, "Close timeout cannot be null");
if (timeout.isNegative() || timeout.isZero()) {
throw new IllegalArgumentException("Close timeout must be positive");
}
this.closeTimeout = timeout;
return this;
}
/**
* Builds a new ConnectionConfig instance with the configured values.
*
* @return A new ConnectionConfig instance
*/
public ConnectionConfig build() {
return new ConnectionConfig(this);
}
}
}