/* * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl-2.1.html * * This library 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 * Lesser General Public License for more details. * * Contributors: * Florent Guillaume */ package org.nuxeo.ecm.core.persistence; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import javax.naming.NamingException; import javax.transaction.Status; import javax.transaction.SystemException; import javax.transaction.Transaction; import org.hibernate.HibernateException; import org.hibernate.cfg.Environment; import org.hibernate.connection.ConnectionProvider; import org.hibernate.connection.DatasourceConnectionProvider; import org.nuxeo.runtime.datasource.ConnectionHelper; import org.nuxeo.runtime.transaction.TransactionHelper; /** * ConnectionProvider for Hibernate that looks up the connection in a * thread-local location, in order to share all connections to the database and * to avoid the need for XA datasources. * * @since 5.7 */ public class NuxeoConnectionProvider implements ConnectionProvider { /** * Delegate to do a standard Hibernate ConnectionProvider when no Nuxeo * connection is available. */ protected DatasourceConnectionProvider dscp; /** * The application-server-specific JNDI name for the datasource. */ protected String dataSourceName; /** * Whether we have switched the connection autoCommit=false and must commit * it on release. */ protected boolean began; @Override public void configure(Properties props) throws HibernateException { dscp = new DatasourceConnectionProvider(); dscp.configure(props); dataSourceName = props.getProperty(Environment.DATASOURCE); } @Override public Connection getConnection() throws SQLException { // try single-datasource non-XA mode Connection connection = ConnectionHelper.getConnection(dataSourceName); if (connection == null) { // standard datasource usage connection = dscp.getConnection(); } begin(connection); return connection; } @Override public void closeConnection(Connection connection) throws SQLException { try { commit(connection); } finally { connection.close(); } } /** * If there is a transaction active, make the connection use it by switching * to autoCommit=false */ private void begin(Connection connection) throws SQLException { began = false; if (!connection.getAutoCommit()) { // setAutoCommit(false) already done by container // so presumably on connection close the container // will do the right thing and commit return; } try { Transaction transaction = TransactionHelper.lookupTransactionManager().getTransaction(); if (transaction != null && transaction.getStatus() == Status.STATUS_ACTIVE) { connection.setAutoCommit(false); began = true; } } catch (NamingException e) { // ignore } catch (SystemException e) { // ignore } } /** * If we previously switched to autoCommit=false, then now is the time to * commit. */ private void commit(Connection connection) throws SQLException { if (began) { began = false; connection.commit(); } } @Override public void close() throws HibernateException { } @Override public boolean supportsAggressiveRelease() { // don't try to close the connection after each statement // (not used if connection release mode is auto) return false; } }