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

herddb.jdbc.BasicHerdDBDataSource Maven / Gradle / Ivy

The newest version!
/*
 Licensed to Diennea S.r.l. under one
 or more contributor license agreements. See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership. Diennea S.r.l. licenses this file
 to you 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 herddb.jdbc;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import herddb.client.ClientConfiguration;
import herddb.client.ClientSideMetadataProviderException;
import herddb.client.HDBClient;
import herddb.client.HDBConnection;
import herddb.client.HDBException;
import herddb.model.TableSpace;
import herddb.utils.QueryParser;
import java.io.Closeable;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * HerdDB DataSource
 *
 * @author enrico.olivelli
 */
public class BasicHerdDBDataSource implements javax.sql.DataSource, AutoCloseable, Closeable {

    protected HDBClient client;
    protected final Properties properties = new Properties();
    protected int loginTimeout;
    protected int maxActive = 200;
    private boolean autoClose;
    private final AtomicInteger activeCount = new AtomicInteger();
    private Consumer onAutoClose = BasicHerdDBDataSource::close;
    private static final Logger LOGGER = Logger.getLogger(BasicHerdDBDataSource.class.getName());
    protected String url;
    protected String defaultSchema = TableSpace.DEFAULT;
    private String waitForTableSpace = "";
    private int waitForTableSpaceTimeout = 60000;
    private boolean discoverTableSpaceFromQuery = true;
    private HDBConnection connection;
    private boolean poolConnections = true;
    private ConnectionsPoolRuntime poolRuntime;

    private synchronized HDBConnection getHDBConnection() {
        if (connection == null) {
            HDBClient _client = getClient();
            HDBConnection _connection = _client.openConnection();
            _connection.setDiscoverTablespaceFromSql(false);
            connection = _connection;
        }
        return connection;
    }

    public synchronized int getWaitForTableSpaceTimeout() {
        return waitForTableSpaceTimeout;
    }

    public synchronized void setWaitForTableSpaceTimeout(int waitForTableSpaceTimeout) {
        this.waitForTableSpaceTimeout = waitForTableSpaceTimeout;
    }

    public synchronized String getWaitForTableSpace() {
        return waitForTableSpace;
    }

    public synchronized void setWaitForTableSpace(String waitForTableSpace) {
        this.waitForTableSpace = waitForTableSpace;
    }

    public synchronized boolean isDiscoverTableSpaceFromQuery() {
        return discoverTableSpaceFromQuery;
    }

    public synchronized void setDiscoverTableSpaceFromQuery(boolean discoverTableSpaceFromQuery) {
        this.discoverTableSpaceFromQuery = discoverTableSpaceFromQuery;
    }

    protected BasicHerdDBDataSource() {
    }

    public BasicHerdDBDataSource(HDBClient client) {
        if (client == null) {
            throw new NullPointerException();
        }
        this.client = client;
    }

    public synchronized int getMaxActive() {
        return maxActive;
    }

    public synchronized void setMaxActive(int maxActive) {
        this.maxActive = maxActive;
    }

    public String getDefaultSchema() {
        return defaultSchema;
    }

    public void setDefaultSchema(String defaultSchema) {
        this.defaultSchema = defaultSchema;
    }

    public synchronized String getUsername() {
        if (client != null) {
            return client.getConfiguration().getString(ClientConfiguration.PROPERTY_CLIENT_USERNAME, ClientConfiguration.PROPERTY_CLIENT_USERNAME_DEFAULT);
        } else {
            return properties.getProperty(ClientConfiguration.PROPERTY_CLIENT_USERNAME, ClientConfiguration.PROPERTY_CLIENT_USERNAME_DEFAULT);
        }
    }

    public synchronized void setUsername(String username) {
        properties.put(ClientConfiguration.PROPERTY_CLIENT_USERNAME, username);
        if (client != null) {
            client.getConfiguration().set(ClientConfiguration.PROPERTY_CLIENT_USERNAME, username);
        }
    }

    public synchronized String getPassword() {
        if (client != null) {
            return client.getConfiguration().getString(ClientConfiguration.PROPERTY_CLIENT_PASSWORD, ClientConfiguration.PROPERTY_CLIENT_PASSWORD_DEFAULT);
        } else {
            return properties.getProperty(ClientConfiguration.PROPERTY_CLIENT_PASSWORD, ClientConfiguration.PROPERTY_CLIENT_PASSWORD_DEFAULT);
        }
    }

    public synchronized void setPassword(String password) {
        properties.put(ClientConfiguration.PROPERTY_CLIENT_PASSWORD, password);
        if (client != null) {
            client.getConfiguration().set(ClientConfiguration.PROPERTY_CLIENT_PASSWORD, password);
        }
    }

    public synchronized String getUrl() {
        return url;
    }

    @SuppressFBWarnings("IS2_INCONSISTENT_SYNC") // sb is lost by the lambda of forEach and does not see we are still in a synchronized block
    public synchronized void setUrl(String url) {
        this.url = url;
        if (client != null) {
            client.getConfiguration().set(ClientConfiguration.PROPERTY_CLIENT_INITIALIZED, "true");
        }
        QueryParser.parseQueryKeyPairs(url).forEach(pair -> {
            if (pair[0].startsWith("client.") && client != null) {
                client.getConfiguration().set(pair[0], pair[1]);
            } else {
                properties.setProperty(pair[0], pair[1]);
            }
        });
    }

    public synchronized boolean isPoolConnections() {
        return poolConnections;
    }

    public synchronized void setPoolConnections(boolean poolConnections) {
        if (client != null || poolRuntime != null) {
            throw new IllegalStateException("Cannot set poolConections=" + poolConnections + " once bootstrap is completed");
        }
        this.poolConnections = poolConnections;
    }

    public Properties getProperties() {
        return properties;
    }

    protected synchronized void doWaitForTableSpace() throws SQLException {
        if (waitForTableSpaceTimeout > 0 && !waitForTableSpace.isEmpty()) {
            try (HDBConnection con = client.openConnection()) {
                con.waitForTableSpace(waitForTableSpace, waitForTableSpaceTimeout);
            } catch (HDBException | ClientSideMetadataProviderException err) {
                throw new SQLException(err);
            }
        }
    }

    protected synchronized void ensureClient() throws SQLException {
        if (client == null) {
            ClientConfiguration clientConfiguration = new ClientConfiguration(properties);
            Properties propsNoPassword = new Properties();
            propsNoPassword.putAll(properties);
            propsNoPassword.setProperty("password", "---");
            LOGGER.log(Level.INFO, "Booting HerdDB Client, url:" + url + ", properties:" + propsNoPassword + " clientConfig " + clientConfiguration);
            try {
                clientConfiguration.readJdbcUrl(url);
            } catch (RuntimeException err) {
                throw new SQLException(err);
            }
            autoClose = clientConfiguration.getBoolean("autoClose", isAutoClose());
            if (properties.containsKey("discoverTableSpaceFromQuery")) {
                this.discoverTableSpaceFromQuery = clientConfiguration.getBoolean("discoverTableSpaceFromQuery", true);
            }
            properties.stringPropertyNames().stream()
                    .filter(it -> it.startsWith("client."))
                    .forEach(key -> clientConfiguration.set(key, properties.getProperty(key)));
            client = new HDBClient(clientConfiguration);
        }
        if (poolRuntime == null) {
            poolConnections = Boolean.parseBoolean(properties.getProperty("poolConnections", poolConnections + ""));
            if (properties.containsKey("maxActive")) {
                this.maxActive = Integer.parseInt(properties.getProperty("maxActive", maxActive + ""));
            }
            if (!poolConnections) {
                poolRuntime = null;
            } else {
                poolRuntime = new ConnectionsPoolRuntime(this);
            }
        }
    }

    protected synchronized void ensureConnection() throws SQLException {
         ensureClient();
    }

    public synchronized HDBClient getClient() {
        return client;
    }

    public synchronized void setClient(HDBClient client) {
        this.client = client;
    }

    @Override
    public Connection getConnection() throws SQLException {
        return getConnection(null, null);
    }

    HerdDBConnection makeConnection() throws SQLException {
        return new HerdDBConnection(BasicHerdDBDataSource.this, getHDBConnection(), defaultSchema);
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        ensureConnection();
        try {
            Connection res;
            if (!isPoolConnections()) {
                res = makeConnection();
            } else {
                res = getPoolRuntime().borrowObject();
            }
            activeCount.incrementAndGet();
            return res;
        } catch (Exception err) {
            throw new SQLException(err);
        }
    }

    private PrintWriter logWriter;

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return logWriter;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {
        this.logWriter = out;
    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {
        this.loginTimeout = seconds;
    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return loginTimeout;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return LOGGER;
    }

    @Override
    public  T unwrap(Class iface) throws SQLException {
        return (T) this;
    }

    @Override
    public boolean isWrapperFor(Class iface) throws SQLException {
        return false;
    }

    public synchronized boolean isAutoClose() {
        return autoClose;
    }

    public synchronized void setAutoClose(boolean autoClose) {
        this.autoClose = autoClose;
    }

    public synchronized void setOnAutoClose(Consumer onAutoClose) {
        this.onAutoClose = onAutoClose;
    }

    @Override
    public synchronized void close() {
        if (client != null) {
            client.close();
            client = null;
        }
    }

    void releaseConnection(HerdDBConnection connection) {
        if (isPoolConnections()) {
            getPoolRuntime().returnObject(connection);
        }
        if (activeCount.decrementAndGet() == 0) {
            performAutoClose();
        }
    }

    private synchronized void performAutoClose() {
        if (autoClose) {
            if (onAutoClose != null) {
                onAutoClose.accept(this);
            }
        }
    }

    public synchronized ConnectionsPoolRuntime getPoolRuntime() {
        return poolRuntime;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy