/* * Copyright 2004-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.lucene.store.jdbc.datasource; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; import org.apache.lucene.store.jdbc.JdbcStoreException; /** * A set of Jdbc <code>DataSource</code> utilities. * * @author kimchy */ public abstract class DataSourceUtils { private static Class springConnectionProxyClass; private static Method springConnectionProxy; static { try { springConnectionProxyClass = Class.forName("org.springframework.jdbc.datasource.ConnectionProxy"); springConnectionProxy = springConnectionProxyClass.getMethod("getTargetConnection"); } catch (Exception e) { springConnectionProxy = null; springConnectionProxyClass = null; } } /** * Returns <code>true</code> if the connection was created by the {@link TransactionAwareDataSourceProxy} and it * controls the connection (i.e. it is the most outer connection created). */ public static boolean controlConnection(Connection connection) { return ((connection instanceof ConnectionProxy) && ((ConnectionProxy) connection).controlConnection()); } /** * Returns a jdbc connection, and in case of failure, wraps the sql * exception with a Jdbc device exception. */ public static Connection getConnection(DataSource dataSource) throws JdbcStoreException { try { return dataSource.getConnection(); } catch (SQLException e) { throw new JdbcStoreException("Failed to open jdbc connection", e); } } /** * Close the given JDBC connection and ignore any thrown exception. This is * useful for typical finally blocks in manual JDBC code. * <p/> * Will only close the connection under two conditions: * If the connection was not created by the {@link TransactionAwareDataSourceProxy}, or if it was created * by {@link TransactionAwareDataSourceProxy}, and the connection controls the connection * (i.e. it is the most outer connection created). */ public static void releaseConnection(Connection con) { if (con == null) { return; } if (!(con instanceof ConnectionProxy) || controlConnection(con)) { try { con.close(); } catch (SQLException ex) { //do nothing } catch (RuntimeException ex) { // do nothing } } } /** * Commits the connection only if the connection is controlled by us. The connection is controlled if it is * the <code>TransactionAwareDataSourceProxy</code> and it is the most outer connection in the tree of connections * the <code>TransactionAwareDataSourceProxy</code> returned. */ public static void commitConnectionIfPossible(Connection con) throws JdbcStoreException { try { if (con != null && controlConnection(con)) { con.commit(); } } catch (SQLException e) { throw new JdbcStoreException("Failed to commit jdbc connection", e); } } /** * Same as {@link #commitConnectionIfPossible(java.sql.Connection)}, only does not throw an exception */ public static void safeCommitConnectionIfPossible(Connection con) { try { if (con != null && controlConnection(con)) { con.commit(); } } catch (SQLException e) { safeRollbackConnectionIfPossible(con); } } /** * Tollbacks the connection only if the connection is controlled by us. The connection is controlled if it is * the <code>TransactionAwareDataSourceProxy</code> and it is the most outer connection in the tree of connections * the <code>TransactionAwareDataSourceProxy</code> returned. */ public static void rollbackConnectionIfPossible(Connection con) throws JdbcStoreException { try { if (con != null && controlConnection(con)) { con.rollback(); } } catch (SQLException e) { throw new JdbcStoreException("Failed to rollback jdbc connection", e); } } /** * Same as {@link #rollbackConnectionIfPossible(java.sql.Connection)}, only does not throw an exception. */ public static void safeRollbackConnectionIfPossible(Connection con) { try { if (con != null && controlConnection(con)) { con.rollback(); } } catch (SQLException e) { // do nothing } } /** * Close the given JDBC Statement and ignore any thrown exception. This is * useful for typical finally blocks in manual JDBC code. * * @param stmt the JDBC Statement to close */ public static void closeStatement(Statement stmt) { if (stmt != null) { try { stmt.close(); } catch (SQLException ex) { // do nothing } catch (RuntimeException ex) { // do nothing } } } /** * Close the given JDBC ResultSet and ignore any thrown exception. This is * useful for typical finally blocks in manual JDBC code. * * @param rs the JDBC ResultSet to close */ public static void closeResultSet(ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException ex) { // do nothing } catch (RuntimeException ex) { // do nothing } } } /** * Returns the column index for the guven column name. Note that if there * are two columns with the same name, the first onde index will be * returned. * <p> * <code>-1</code> is returned if none is found. */ public static int getColumnIndexFromColumnName(ResultSetMetaData metaData, String columnName) throws SQLException { for (int i = 1; i <= metaData.getColumnCount(); i++) { String tmpName = metaData.getColumnLabel(i); if (tmpName.equalsIgnoreCase(columnName)) { return i; } } return -1; } public static Connection getTargetConnection(Connection conn) { if (conn instanceof ConnectionProxy) { return getTargetConnection(((ConnectionProxy) conn).getTargetConnection()); } // currently a hack to suppport Spring wrapping of connections. Need to implement a nicer pluggable native extractor if (springConnectionProxy != null && springConnectionProxyClass != null) { if (springConnectionProxyClass.isAssignableFrom(conn.getClass())) { try { return (Connection) springConnectionProxy.invoke(conn); } catch (Exception e) { return conn; } } } return conn; } }