diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/BaseC3P0ConnectionCustomizer.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/BaseC3P0ConnectionCustomizer.java new file mode 100644 index 00000000..2e0549d3 --- /dev/null +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/BaseC3P0ConnectionCustomizer.java @@ -0,0 +1,110 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2025. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.backend.module.rdbms.jdbc; + + +import java.sql.Connection; +import java.sql.Statement; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.kingsrook.qqq.backend.core.utils.CollectionUtils; +import com.mchange.v2.c3p0.ConnectionCustomizer; + + +/******************************************************************************* + ** Basic version of a C3P0 Connection Customizer used by QQQ - that does things + ** expected for an RDBMS backend - specifically: + ** - runs queriesForNewConnections, if they are set. + *******************************************************************************/ +public class BaseC3P0ConnectionCustomizer implements ConnectionCustomizer +{ + private static Map> queriesForNewConnections = new HashMap<>(); + + + + /*************************************************************************** + * + ***************************************************************************/ + @Override + public void onAcquire(Connection connection, String dataSourceIdentityToken) throws Exception + { + List queries = queriesForNewConnections.get(dataSourceIdentityToken); + if(CollectionUtils.nullSafeHasContents(queries)) + { + for(String sql : queries) + { + Statement statement = connection.createStatement(); + statement.execute(sql); + } + } + } + + + + /*************************************************************************** + * + ***************************************************************************/ + @Override + public void onDestroy(Connection connection, String dataSourceIdentityToken) throws Exception + { + ////////// + // noop // + ////////// + } + + + + /*************************************************************************** + * + ***************************************************************************/ + @Override + public void onCheckOut(Connection connection, String dataSourceIdentityToken) throws Exception + { + ////////// + // noop // + ////////// + } + + + + /*************************************************************************** + * + ***************************************************************************/ + @Override + public void onCheckIn(Connection connection, String dataSourceIdentityToken) throws Exception + { + ////////// + // noop // + ////////// + } + + + /*************************************************************************** + * + ***************************************************************************/ + public static void setQueriesForNewConnections(String backendName, List queriesForNewConnections) + { + BaseC3P0ConnectionCustomizer.queriesForNewConnections.put(backendName, queriesForNewConnections); + } + +} diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/C3P0PooledConnectionProvider.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/C3P0PooledConnectionProvider.java index 1a4740e4..e5ea2e2f 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/C3P0PooledConnectionProvider.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/C3P0PooledConnectionProvider.java @@ -26,6 +26,7 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.LinkedHashMap; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.module.rdbms.model.metadata.ConnectionPoolSettings; import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData; import com.mchange.v2.c3p0.ComboPooledDataSource; @@ -110,6 +111,17 @@ public class C3P0PooledConnectionProvider implements ConnectionProviderInterface } } + pool.setIdentityToken(backend.getName()); + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // if the backend specifies queries to run for new connections, then set up a connection customizer to run them // + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if(CollectionUtils.nullSafeHasContents(backend.getQueriesForNewConnections())) + { + BaseC3P0ConnectionCustomizer.setQueriesForNewConnections(backend.getName(), backend.getQueriesForNewConnections()); + pool.setConnectionCustomizerClassName(BaseC3P0ConnectionCustomizer.class.getName()); + } + customizePool(pool); this.connectionPool = pool; diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/SimpleConnectionProvider.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/SimpleConnectionProvider.java index 264f5528..870da925 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/SimpleConnectionProvider.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/jdbc/SimpleConnectionProvider.java @@ -25,6 +25,8 @@ package com.kingsrook.qqq.backend.module.rdbms.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; +import java.sql.Statement; +import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData; import static com.kingsrook.qqq.backend.module.rdbms.jdbc.ConnectionManager.getJdbcUrl; @@ -57,7 +59,28 @@ public class SimpleConnectionProvider implements ConnectionProviderInterface public Connection getConnection() throws SQLException { String jdbcURL = getJdbcUrl(backend); - return DriverManager.getConnection(jdbcURL, backend.getUsername(), backend.getPassword()); + Connection connection = DriverManager.getConnection(jdbcURL, backend.getUsername(), backend.getPassword()); + + if(CollectionUtils.nullSafeHasContents(backend.getQueriesForNewConnections())) + { + runQueriesForNewConnections(connection); + } + + return (connection); + } + + + + /*************************************************************************** + * + ***************************************************************************/ + private void runQueriesForNewConnections(Connection connection) throws SQLException + { + for(String sql : backend.getQueriesForNewConnections()) + { + Statement statement = connection.createStatement(); + statement.execute(sql); + } } } diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/model/metadata/RDBMSBackendMetaData.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/model/metadata/RDBMSBackendMetaData.java index 110db12d..b5b623b6 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/model/metadata/RDBMSBackendMetaData.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/model/metadata/RDBMSBackendMetaData.java @@ -22,6 +22,7 @@ package com.kingsrook.qqq.backend.module.rdbms.model.metadata; +import java.util.List; import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter; import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; @@ -49,6 +50,8 @@ public class RDBMSBackendMetaData extends QBackendMetaData private RDBMSBackendMetaData readOnlyBackendMetaData; + private List queriesForNewConnections = null; + /////////////////////////////////////////////////////////// // define well-known (and fully supported) vendor values // /////////////////////////////////////////////////////////// @@ -453,4 +456,34 @@ public class RDBMSBackendMetaData extends QBackendMetaData return (this); } + /******************************************************************************* + ** Getter for queriesForNewConnections + *******************************************************************************/ + public List getQueriesForNewConnections() + { + return (this.queriesForNewConnections); + } + + + + /******************************************************************************* + ** Setter for queriesForNewConnections + *******************************************************************************/ + public void setQueriesForNewConnections(List queriesForNewConnections) + { + this.queriesForNewConnections = queriesForNewConnections; + } + + + + /******************************************************************************* + ** Fluent setter for queriesForNewConnections + *******************************************************************************/ + public RDBMSBackendMetaData withQueriesForNewConnections(List queriesForNewConnections) + { + this.queriesForNewConnections = queriesForNewConnections; + return (this); + } + + }