All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jio.jdbc.DatasourceBuilder Maven / Gradle / Ivy

There is a newer version: 3.0.0-RC2
Show newest version
package jio.jdbc;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

import javax.sql.DataSource;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * A builder class for creating and configuring a {@link javax.sql.DataSource} using HikariCP. The creation of the
 * DataSource is lazy, and a double-check idiom is used to ensure thread safety during creation.
 */
public final class DatasourceBuilder implements Supplier {
    private final String user;
    private final byte[] sec;
    private final String url;
    private final int DEFAULT_MAX_POOL_SIZE = 20;
    private volatile HikariDataSource dataSource;
    private int connectionTimeout;
    private int maxPoolSize = DEFAULT_MAX_POOL_SIZE;
    private Consumer addProps;

    /**
     * Constructs a {@code DatasourceBuilder} with the specified user, password, and JDBC URL.
     *
     * @param user The username for database connection.
     * @param sec  The password for database connection as a byte array.
     * @param url  The JDBC URL for connecting to the database.
     * @throws IllegalArgumentException If the password is empty or the URL is empty.
     */
    public DatasourceBuilder(final String user,
                             final byte[] sec,
                             final String url
                            ) {
        this.user = Objects.requireNonNull(user);
        this.sec = Objects.requireNonNull(sec);
        this.url = Objects.requireNonNull(url);
        if (sec.length == 0) throw new IllegalArgumentException("password is empty");
        if (url.trim().isEmpty()) throw new IllegalArgumentException("url is empty");
        Runtime.getRuntime()
               .addShutdownHook(new Thread(() -> {
                   if (dataSource != null) dataSource.close();
               }));

    }

    /**
     * Sets the connection timeout for the DataSource.
     *
     * @param connectionTimeout The connection timeout in milliseconds.
     * @return This {@code DatasourceBuilder} instance for method chaining.
     * @throws IllegalArgumentException If the connection timeout is less than or equal to 0.
     */
    public DatasourceBuilder setConnectionTimeout(final int connectionTimeout) {
        if (maxPoolSize <= 0) throw new IllegalArgumentException("connectionTimeoutMs <= 0");
        this.connectionTimeout = connectionTimeout;
        return this;
    }

    /**
     * Sets the maximum pool size for the DataSource.
     *
     * @param maxPoolSize The maximum pool size.
     * @return This {@code DatasourceBuilder} instance for method chaining.
     * @throws IllegalArgumentException If the maximum pool size is less than or equal to 0.
     */
    public DatasourceBuilder setMaxPoolSize(final int maxPoolSize) {
        if (maxPoolSize <= 0) throw new IllegalArgumentException("maxPoolSize <= 0");
        this.maxPoolSize = maxPoolSize;
        return this;
    }

    /**
     * Sets additional properties for configuring the HikariConfig.
     *
     * @param addProps The consumer function to apply additional properties to the HikariConfig.
     * @return This {@code DatasourceBuilder} instance for method chaining.
     */
    public DatasourceBuilder setAddProps(final Consumer addProps) {
        this.addProps = Objects.requireNonNull(addProps);
        return this;
    }

    /**
     * Gets the DataSource. The creation of the DataSource is lazy, and a double-check idiom is used for thread safety.
     *
     * @return The configured DataSource.
     */
    @Override
    public DataSource get() {
        var localRef = dataSource;
        if (localRef == null) {
            synchronized (this) {
                localRef = dataSource;
                if (localRef == null) {
                    HikariConfig config = getHikariConfig();
                    dataSource = localRef = new HikariDataSource(config);

                }
            }
        }
        return localRef;

    }

    private HikariConfig getHikariConfig() {
        var config = new HikariConfig();
        config.setJdbcUrl(url);
        config.setUsername(user);
        config.setPassword(new String(sec, StandardCharsets.UTF_8));
        config.setConnectionTimeout(connectionTimeout);
        config.setMaximumPoolSize(maxPoolSize);
        if (addProps != null) addProps.accept(config);
        return config;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy