001/* 002 * (C) Copyright 2012-2016 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Florent Guillaume 018 */ 019package org.nuxeo.runtime.datasource; 020 021import java.sql.Connection; 022import java.sql.SQLException; 023 024import javax.naming.NamingException; 025import javax.sql.DataSource; 026 027import org.apache.commons.dbcp2.managed.BasicManagedDataSource; 028import org.apache.commons.lang3.reflect.MethodUtils; 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.nuxeo.common.utils.JDBCUtils; 032import org.nuxeo.runtime.api.Framework; 033 034/** 035 * Helper to acquire a JDBC {@link Connection} from a datasource name. 036 * 037 * @since 5.7 038 */ 039public class ConnectionHelper { 040 041 private static final Log log = LogFactory.getLog(ConnectionHelper.class); 042 043 /** 044 * Tries to unwrap the connection to get the real physical one (returned by the original datasource). 045 * <p> 046 * This should only be used by code that needs to cast the connection to a driver-specific class to use 047 * driver-specific features. 048 * 049 * @throws SQLException if no actual physical connection was allocated yet 050 */ 051 public static Connection unwrap(Connection connection) throws SQLException { 052 // now try Apache DBCP unwrap (standard or Tomcat), to skip datasource wrapping layers 053 // this needs accessToUnderlyingConnectionAllowed=true in the pool config 054 try { 055 @SuppressWarnings("resource") // not ours to close 056 Connection delegate = (Connection) MethodUtils.invokeMethod(connection, true, "getInnermostDelegate"); 057 if (delegate == null) { 058 log.error("Cannot access underlying connection, you must use " 059 + "accessToUnderlyingConnectionAllowed=true in the pool configuration"); 060 } else { 061 connection = delegate; 062 } 063 } catch (ReflectiveOperationException e) { 064 // ignore missing method, connection not coming from Apache pool 065 } 066 return connection; 067 } 068 069 /** 070 * Gets a new connection for the given dataSource. The connection <strong>MUST</strong> be closed in a finally block 071 * when code is done using it. 072 * 073 * @param dataSourceName the datasource for which the connection is requested 074 * @return a new connection 075 */ 076 public static Connection getConnection(String dataSourceName) throws SQLException { 077 return getConnection(dataSourceName, false); 078 } 079 080 /** 081 * Gets a new connection for the given dataSource. The connection <strong>MUST</strong> be closed in a finally block 082 * when code is done using it. 083 * 084 * @param dataSourceName the datasource for which the connection is requested 085 * @param noSharing {@code true} if this connection must not be shared with others 086 * @return a new connection 087 */ 088 public static Connection getConnection(String dataSourceName, boolean noSharing) throws SQLException { 089 DataSource dataSource = getDataSource(dataSourceName, noSharing); 090 if (dataSource instanceof BasicManagedDataSource) { 091 return dataSource.getConnection(); 092 } else { 093 return JDBCUtils.getConnection(dataSource); 094 } 095 } 096 097 /** 098 * Gets a datasource from a datasource name, or in test mode use test connection parameters. 099 * 100 * @param dataSourceName the datasource name 101 * @return the datasource 102 */ 103 private static DataSource getDataSource(String dataSourceName, boolean noSharing) throws SQLException { 104 try { 105 return DataSourceHelper.getDataSource(dataSourceName, noSharing); 106 } catch (NamingException e) { 107 if (Framework.isTestModeSet()) { 108 String url = Framework.getProperty("nuxeo.test.vcs.url"); 109 String user = Framework.getProperty("nuxeo.test.vcs.user"); 110 String password = Framework.getProperty("nuxeo.test.vcs.password"); 111 if (url != null && user != null) { 112 return new DataSourceFromUrl(url, user, password); // driver? 113 } 114 } 115 throw new SQLException("Cannot find datasource: " + dataSourceName, e); 116 } 117 } 118 119}