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

org.nuiton.topia.persistence.internal.TopiaConnectionProvider Maven / Gradle / Ivy

The newest version!
package org.nuiton.topia.persistence.internal;

/*
 * #%L
 * ToPIA Extension :: API
 * %%
 * Copyright (C) 2018 - 2022 Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.UnknownUnwrapTypeException;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.Stoppable;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * 

* Customized connection provider. *

*

* This provider fix the following bug : http://nuiton.org/issues/show/561 *

* To use this connection provider, add this property to topia configuration *
 * config.setProperty(Environment.CONNECTION_PROVIDER, TopiaConnectionProvider.class.getName());
 * 
* or in a properties file : *
 * hibernate.connection.provider_class=org.nuiton.topia.persistence.internal.TopiaConnectionProvider
 * 
* * @author Tony Chemit - [email protected] * @since 2.5.3 */ public class TopiaConnectionProvider implements ConnectionProvider, Configurable, Stoppable { private static final Logger log = LogManager.getLogger(TopiaConnectionProvider.class); private static final long serialVersionUID = -8190835231054317644L; /** * JDBC url of connection. *

* This is a mandatory hibernate configuration vi the property * {@link Environment#URL}. */ protected String url; /** * All grabbed connection properties */ protected Properties connectionProps; /** * Sql isolation level to use in connection. *

* Can be configured by hibernate property {@link Environment#ISOLATION}. * * @see Connection#getTransactionIsolation() */ protected Integer isolation; /** * auto commit connection state. *

* Can be configured by hibernate property {@link Environment#AUTOCOMMIT}. * * @see Connection#getAutoCommit() */ protected boolean autocommit; /** * Size of connection pool. *

* By default use {@code 20}, can be specify by using the hibernate * configuration property {@link Environment#POOL_SIZE}. */ protected int poolSize; private boolean stopped; /** * Our pool of connections which are not closed and availables. */ protected final List pool; public TopiaConnectionProvider() { pool = new ArrayList<>(); } @Override public void configure(Map configurationValues) throws HibernateException { poolSize = ConfigurationHelper.getInt(AvailableSettings.POOL_SIZE, configurationValues, 20); //default pool size 20 if (log.isDebugEnabled()) { log.debug("Connection pool size: " + poolSize); } autocommit = ConfigurationHelper.getBoolean(AvailableSettings.AUTOCOMMIT, configurationValues); if (log.isDebugEnabled()) { log.debug("autocommit mode: " + autocommit); } isolation = ConfigurationHelper.getInteger(AvailableSettings.ISOLATION, configurationValues); if (isolation != null) { if (log.isDebugEnabled()) { log.debug("JDBC isolation level: " + Environment.isolationLevelToString(isolation)); } } String driverClass = ConfigurationHelper.getString(AvailableSettings.DRIVER, configurationValues); if (driverClass == null) { if (log.isWarnEnabled()) { log.warn("no JDBC Driver class was specified by property " + AvailableSettings.DRIVER); } } else { try { // trying via forName() first to be as close to DriverManager's semantics Class.forName(driverClass); } catch (ClassNotFoundException cnfe) { try { ReflectHelper.classForName(driverClass); } catch (ClassNotFoundException e) { String msg = "JDBC Driver class not found: " + driverClass; log.error(msg, e); throw new HibernateException(msg, e); } } } url = (String) configurationValues.get(AvailableSettings.URL); if (url == null) { String msg = "JDBC URL was not specified by property " + AvailableSettings.URL; if (log.isErrorEnabled()) { log.error(msg); } throw new HibernateException(msg); } connectionProps = ConnectionProviderInitiator.getConnectionProperties(configurationValues); if (log.isDebugEnabled()) { log.debug("using driver: " + driverClass + " at URL: " + url); } // if debug level is enabled, then log the password, otherwise mask it if (log.isTraceEnabled()) { log.debug("connection properties: " + connectionProps); } else if (log.isDebugEnabled()) { log.debug("connection properties: " + ConfigurationHelper.maskOut(connectionProps, "password")); } } @Override public Connection getConnection() throws SQLException { Connection connection = null; synchronized (pool) { // try to use a connection from the pool (if any) while (!pool.isEmpty() && connection == null) { int last = pool.size() - 1; if (log.isTraceEnabled()) { log.trace("using pooled JDBC connection, pool size: " + last); } connection = pool.remove(last); if (connection.isClosed()) { // this connection is closed!, don't use it connection = null; if (log.isDebugEnabled()) { log.debug("Remove already closed connection from pool " + connection); } } } } if (connection == null) { // the pool was empty, creates a new connection if (log.isDebugEnabled()) { log.debug("opening new JDBC connection to " + url); } connection = DriverManager.getConnection(url, connectionProps); } // configure connection if (isolation != null) { connection.setTransactionIsolation(isolation); } if (connection.getAutoCommit() != autocommit) { connection.setAutoCommit(autocommit); } return connection; } @Override public void closeConnection(Connection conn) throws SQLException { if (conn == null) { if (log.isDebugEnabled()) { log.debug("No JDBC connection to close"); } return; } // if connection is already closed, nothing has to be done // we can't keep this connection (and can not be push in pool) if (conn.isClosed()) { if (log.isDebugEnabled()) { log.debug("Connection [" + conn + "] alreay closed!, will not use it any longer "); } return; } // connection was not closed, can push it in the pool (if pool is not // full) synchronized (pool) { int currentSize = pool.size(); if (currentSize < getPoolSize()) { if (log.isTraceEnabled()) { log.trace("returning connection to pool, pool size: " + (currentSize + 1)); } pool.add(conn); return; } } // pool was full, must release the connection which will be loose if (log.isDebugEnabled()) { log.debug("closing JDBC connection"); } conn.close(); } @Override protected void finalize() throws Throwable { if (!stopped) { stop(); } super.finalize(); } @Override public void stop() { if (log.isDebugEnabled()) { log.debug("cleaning up connection pool: " + url); } for (Connection connection : pool) { try { connection.close(); } catch (SQLException sqle) { if (log.isWarnEnabled()) { log.warn("problem closing pooled connection", sqle); } } } pool.clear(); stopped = true; } @Override public boolean supportsAggressiveRelease() { return false; } public String getUrl() { return url; } public Properties getConnectionProps() { return connectionProps; } public Integer getIsolation() { return isolation; } public List getPool() { return pool; } public int getPoolSize() { return poolSize; } public boolean isAutocommit() { return autocommit; } @Override public boolean isUnwrappableAs(Class unwrapType) { return ConnectionProvider.class.equals(unwrapType) || getClass().isAssignableFrom(unwrapType); } @Override @SuppressWarnings({"unchecked"}) public T unwrap(Class unwrapType) { if (ConnectionProvider.class.equals(unwrapType) || getClass().isAssignableFrom(unwrapType)) { return (T) this; } else { throw new UnknownUnwrapTypeException(unwrapType); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy