From 6e5ebeb520c298f3acaad1424fb0b1e919aa796d Mon Sep 17 00:00:00 2001 From: serge-rider Date: Thu, 30 Apr 2020 21:44:13 +0300 Subject: [PATCH] #8 Database schema create --- .../sample-databases/cloudbeaver-sample.conf | 9 +- .../META-INF/MANIFEST.MF | 4 +- .../src/io/cloudbeaver/server/CBDatabase.java | 91 ++++++++++++++++--- .../cloudbeaver/server/CBDatabaseConfig.java | 40 +++++--- .../CloudbeaverServer.product.launch | 2 +- 5 files changed, 113 insertions(+), 33 deletions(-) diff --git a/samples/sample-databases/cloudbeaver-sample.conf b/samples/sample-databases/cloudbeaver-sample.conf index 662b6de7a9..5e4a55c4c5 100644 --- a/samples/sample-databases/cloudbeaver-sample.conf +++ b/samples/sample-databases/cloudbeaver-sample.conf @@ -20,7 +20,14 @@ driver="h2_embedded", url: "jdbc:h2:${workspace}/.data/cb.h2.dat", - createDatabase: true + createDatabase: true, + + pool: { + minIdleConnections: 4, + maxIdleConnections: 10, + maxConnections: 100, + validationQuery: "SELECT 1" + } } }, app: { diff --git a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF index 2d5ebf88c8..49e3178fe8 100644 --- a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF @@ -23,9 +23,9 @@ Require-Bundle: org.eclipse.core.runtime;visibility:=reexport, org.eclipse.jetty.servlet;visibility:=reexport, org.eclipse.jetty.util;visibility:=reexport, com.google.gson;visibility:=reexport, - org.jkiss.bundle.graphql.java;visibility:=reexport + org.jkiss.bundle.graphql.java;visibility:=reexport, + org.jkiss.bundle.apache.dbcp Export-Package: io.cloudbeaver, - io.cloudbeaver.api, io.cloudbeaver.server, io.cloudbeaver.model, io.cloudbeaver.model.resources, diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabase.java index 46fb4e472e..af46606c16 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabase.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabase.java @@ -16,21 +16,28 @@ */ package io.cloudbeaver.server; +import org.apache.commons.dbcp2.DriverConnectionFactory; +import org.apache.commons.dbcp2.PoolableConnection; +import org.apache.commons.dbcp2.PoolableConnectionFactory; +import org.apache.commons.dbcp2.PoolingDataSource; +import org.apache.commons.pool2.impl.GenericObjectPool; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.DBConstants; -import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration; import org.jkiss.dbeaver.model.runtime.LoggingProgressMonitor; import org.jkiss.dbeaver.registry.DataSourceProviderRegistry; import org.jkiss.dbeaver.registry.driver.DriverDescriptor; +import org.jkiss.dbeaver.utils.ContentUtils; import org.jkiss.dbeaver.utils.GeneralUtils; import org.jkiss.dbeaver.utils.SystemVariablesResolver; import org.jkiss.utils.CommonUtils; +import org.jkiss.utils.IOUtils; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.Driver; -import java.sql.SQLException; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.sql.*; import java.util.Properties; /** @@ -38,16 +45,21 @@ import java.util.Properties; */ public class CBDatabase { private static final Log log = Log.getLog(CBDatabase.class); + public static final String SCHEMA_SQL_PATH = "db/cb-schema.sql"; private final CBApplication application; private final CBDatabaseConfig databaseConfiguration; - private Connection connection; + private PoolingDataSource cdDataSource; public CBDatabase(CBApplication application, CBDatabaseConfig databaseConfiguration) { this.application = application; this.databaseConfiguration = databaseConfiguration; } + public PoolingDataSource getConnectionPool() { + return cdDataSource; + } + void connect() throws DBException { if (CommonUtils.isEmpty(databaseConfiguration.getDriver())) { throw new DBException("Database driver not specified"); @@ -71,23 +83,72 @@ public class CBDatabase { dbProperties.put(DBConstants.DATA_SOURCE_PROPERTY_PASSWORD, databaseConfiguration.getPassword()); } } - try { - connection = driverInstance.connect(dbURL, dbProperties); - } catch (SQLException e) { - throw new DBException("Error connecting to '" + dbURL + "'", e); - } - try { + // Create connection pool with custom connection factory + DriverConnectionFactory conFactory = new DriverConnectionFactory(driverInstance, dbURL, dbProperties); + PoolableConnectionFactory pcf = new PoolableConnectionFactory(conFactory, null); + pcf.setValidationQuery(databaseConfiguration.getPool().getValidationQuery()); + + GenericObjectPoolConfig config = new GenericObjectPoolConfig<>(); + config.setMinIdle(databaseConfiguration.getPool().getMinIdleConnections()); + config.setMaxIdle(databaseConfiguration.getPool().getMaxIdleConnections()); + config.setMaxTotal(databaseConfiguration.getPool().getMaxConnections()); + GenericObjectPool connectionPool = new GenericObjectPool<>(pcf, config); + pcf.setPool(connectionPool); + cdDataSource = new PoolingDataSource<>(connectionPool); + + try (Connection connection = cdDataSource.getConnection()) { DatabaseMetaData metaData = connection.getMetaData(); log.debug("Connected to " + metaData.getDatabaseProductName() + " " + metaData.getDatabaseProductVersion()); } catch (SQLException e) { - throw new DBException("Error getting database metadata", e); + throw new DBException("Error connecting to '" + dbURL + "'", e); } checkDatabaseStructure(); } - private void checkDatabaseStructure() { - + private void checkDatabaseStructure() throws DBException { + try (Connection connection = cdDataSource.getConnection()) { + boolean schemaExists = false; + try (Statement dbStat = connection.createStatement()) { + try (ResultSet dbResult = dbStat.executeQuery("SELECT * FROM CB_SERVER")) { + schemaExists = true; + } catch (SQLException e) { + schemaExists = false; + } + } + if (!schemaExists) { + createDatabaseSchema(connection); + } + } catch (SQLException e) { + throw new DBException("Error initializing schema", e); + } } + + private void createDatabaseSchema(Connection connection) throws DBException { + log.debug("Create database schema"); + InputStream ddlStream = getClass().getClassLoader().getResourceAsStream(SCHEMA_SQL_PATH); + if (ddlStream == null) { + throw new DBException("Can't find schema file " + SCHEMA_SQL_PATH); + } + try { + ByteArrayOutputStream ddlBuffer = new ByteArrayOutputStream(); + IOUtils.copyStream(ddlStream, ddlBuffer); + String ddl = new String(ddlBuffer.toByteArray(), StandardCharsets.UTF_8); + for (String line : ddl.split(";")) { + line = line.trim(); + if (line.isEmpty()) { + continue; + } + try (Statement dbStat = connection.createStatement()) { + dbStat.execute(line); + } + } + } catch (Exception e) { + throw new DBException("Error processing schema DDL", e); + } finally { + ContentUtils.close(ddlStream); + } + } + } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabaseConfig.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabaseConfig.java index 75fdd221c3..7629fc0015 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabaseConfig.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabaseConfig.java @@ -31,6 +31,30 @@ public class CBDatabaseConfig { private String password; private boolean createDatabase; + private final Pool pool = new Pool(); + + public static class Pool { + private int minIdleConnections = 2; + private int maxIdleConnections = 10; + private int maxConnections = 1000; + private String validationQuery = "SELECT 1"; + + public int getMinIdleConnections() { + return minIdleConnections; + } + + public int getMaxIdleConnections() { + return maxIdleConnections; + } + + public int getMaxConnections() { + return maxConnections; + } + + public String getValidationQuery() { + return validationQuery; + } + } public String getDriver() { return driver; @@ -44,31 +68,19 @@ public class CBDatabaseConfig { return url; } - public void setUrl(String url) { - this.url = url; - } - public String getUser() { return user; } - public void setUser(String user) { - this.user = user; - } - public String getPassword() { return password; } - public void setPassword(String password) { - this.password = password; - } - public boolean isCreateDatabase() { return createDatabase; } - public void setCreateDatabase(boolean createDatabase) { - this.createDatabase = createDatabase; + public Pool getPool() { + return pool; } } diff --git a/server/product/web-server/CloudbeaverServer.product.launch b/server/product/web-server/CloudbeaverServer.product.launch index e90dba9c53..c68afd928c 100644 --- a/server/product/web-server/CloudbeaverServer.product.launch +++ b/server/product/web-server/CloudbeaverServer.product.launch @@ -30,7 +30,7 @@ - +