package org.davidmoten.rx.jdbc.pool.internal; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.atomic.AtomicBoolean; import org.davidmoten.rx.jdbc.ConnectionProvider; import org.davidmoten.rx.jdbc.exceptions.SQLRuntimeException; import org.davidmoten.rx.jdbc.internal.DelegatedConnection; import org.davidmoten.rx.pool.Member; import org.davidmoten.rx.pool.Pool; import com.github.davidmoten.guavamini.Preconditions; import io.reactivex.Single; import io.reactivex.plugins.RxJavaPlugins; public final class ConnectionProviderBlockingPool implements Pool<Connection> { private final ConnectionProvider connectionProvider; public ConnectionProviderBlockingPool(ConnectionProvider connectionProvider) { this.connectionProvider = connectionProvider; } @Override public Single<Member<Connection>> member() { return Single.fromCallable(() -> new MemberWithValueConnection(connectionProvider)); } @Override public void close() throws Exception { connectionProvider.close(); } static final class MemberWithValueConnection implements Member<Connection>, DelegatedConnection { private final ConnectionProvider connectionProvider; public MemberWithValueConnection(ConnectionProvider cp) { this.connectionProvider = cp; } volatile PooledConnection connection; final AtomicBoolean hasConnection = new AtomicBoolean(); @Override public Connection con() { if (hasConnection.compareAndSet(false, true)) { // blocking Connection c = connectionProvider.get(); Preconditions.checkNotNull(c, "connectionProvider should not return null"); connection = new PooledConnection(c, this); } return connection; } @Override public void checkin() { try { connection.con().close(); } catch (SQLException e) { throw new SQLRuntimeException(e); } } @Override public Connection value() { return con(); } @Override public void disposeValue() { try { connection.con().close(); } catch (SQLException e) { RxJavaPlugins.onError(e); } } } }