001: /*
002: * Copyright 2004-2006 the original author or authors.
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:
017: package org.apache.lucene.store.jdbc.datasource;
018:
019: import java.lang.reflect.Method;
020: import java.sql.Connection;
021: import java.sql.ResultSet;
022: import java.sql.ResultSetMetaData;
023: import java.sql.SQLException;
024: import java.sql.Statement;
025: import javax.sql.DataSource;
026:
027: import org.apache.lucene.store.jdbc.JdbcStoreException;
028:
029: /**
030: * A set of Jdbc <code>DataSource</code> utilities.
031: *
032: * @author kimchy
033: */
034: public abstract class DataSourceUtils {
035:
036: private static Class springConnectionProxyClass;
037:
038: private static Method springConnectionProxy;
039:
040: static {
041: try {
042: springConnectionProxyClass = Class
043: .forName("org.springframework.jdbc.datasource.ConnectionProxy");
044: springConnectionProxy = springConnectionProxyClass
045: .getMethod("getTargetConnection");
046: } catch (Exception e) {
047: springConnectionProxy = null;
048: springConnectionProxyClass = null;
049: }
050: }
051:
052: /**
053: * Returns <code>true</code> if the connection was created by the {@link TransactionAwareDataSourceProxy} and it
054: * controls the connection (i.e. it is the most outer connection created).
055: */
056: public static boolean controlConnection(Connection connection) {
057: return ((connection instanceof ConnectionProxy) && ((ConnectionProxy) connection)
058: .controlConnection());
059: }
060:
061: /**
062: * Returns a jdbc connection, and in case of failure, wraps the sql
063: * exception with a Jdbc device exception.
064: */
065: public static Connection getConnection(DataSource dataSource)
066: throws JdbcStoreException {
067: try {
068: return dataSource.getConnection();
069: } catch (SQLException e) {
070: throw new JdbcStoreException(
071: "Failed to open jdbc connection", e);
072: }
073: }
074:
075: /**
076: * Close the given JDBC connection and ignore any thrown exception. This is
077: * useful for typical finally blocks in manual JDBC code.
078: * <p/>
079: * Will only close the connection under two conditions:
080: * If the connection was not created by the {@link TransactionAwareDataSourceProxy}, or if it was created
081: * by {@link TransactionAwareDataSourceProxy}, and the connection controls the connection
082: * (i.e. it is the most outer connection created).
083: */
084: public static void releaseConnection(Connection con) {
085: if (con == null) {
086: return;
087: }
088: if (!(con instanceof ConnectionProxy) || controlConnection(con)) {
089: try {
090: con.close();
091: } catch (SQLException ex) {
092: //do nothing
093: } catch (RuntimeException ex) {
094: // do nothing
095: }
096: }
097: }
098:
099: /**
100: * Commits the connection only if the connection is controlled by us. The connection is controlled if it is
101: * the <code>TransactionAwareDataSourceProxy</code> and it is the most outer connection in the tree of connections
102: * the <code>TransactionAwareDataSourceProxy</code> returned.
103: */
104: public static void commitConnectionIfPossible(Connection con)
105: throws JdbcStoreException {
106: try {
107: if (con != null && controlConnection(con)) {
108: con.commit();
109: }
110: } catch (SQLException e) {
111: throw new JdbcStoreException(
112: "Failed to commit jdbc connection", e);
113: }
114: }
115:
116: /**
117: * Same as {@link #commitConnectionIfPossible(java.sql.Connection)}, only does not throw an exception
118: */
119: public static void safeCommitConnectionIfPossible(Connection con) {
120: try {
121: if (con != null && controlConnection(con)) {
122: con.commit();
123: }
124: } catch (SQLException e) {
125: safeRollbackConnectionIfPossible(con);
126: }
127: }
128:
129: /**
130: * Tollbacks the connection only if the connection is controlled by us. The connection is controlled if it is
131: * the <code>TransactionAwareDataSourceProxy</code> and it is the most outer connection in the tree of connections
132: * the <code>TransactionAwareDataSourceProxy</code> returned.
133: */
134: public static void rollbackConnectionIfPossible(Connection con)
135: throws JdbcStoreException {
136: try {
137: if (con != null && controlConnection(con)) {
138: con.rollback();
139: }
140: } catch (SQLException e) {
141: throw new JdbcStoreException(
142: "Failed to rollback jdbc connection", e);
143: }
144: }
145:
146: /**
147: * Same as {@link #rollbackConnectionIfPossible(java.sql.Connection)}, only does not throw an exception.
148: */
149: public static void safeRollbackConnectionIfPossible(Connection con) {
150: try {
151: if (con != null && controlConnection(con)) {
152: con.rollback();
153: }
154: } catch (SQLException e) {
155: // do nothing
156: }
157: }
158:
159: /**
160: * Close the given JDBC Statement and ignore any thrown exception. This is
161: * useful for typical finally blocks in manual JDBC code.
162: *
163: * @param stmt the JDBC Statement to close
164: */
165: public static void closeStatement(Statement stmt) {
166: if (stmt != null) {
167: try {
168: stmt.close();
169: } catch (SQLException ex) {
170: // do nothing
171: } catch (RuntimeException ex) {
172: // do nothing
173: }
174: }
175: }
176:
177: /**
178: * Close the given JDBC ResultSet and ignore any thrown exception. This is
179: * useful for typical finally blocks in manual JDBC code.
180: *
181: * @param rs the JDBC ResultSet to close
182: */
183: public static void closeResultSet(ResultSet rs) {
184: if (rs != null) {
185: try {
186: rs.close();
187: } catch (SQLException ex) {
188: // do nothing
189: } catch (RuntimeException ex) {
190: // do nothing
191: }
192: }
193: }
194:
195: /**
196: * Returns the column index for the guven column name. Note that if there
197: * are two columns with the same name, the first onde index will be
198: * returned.
199: * <p>
200: * <code>-1</code> is returned if none is found.
201: */
202: public static int getColumnIndexFromColumnName(
203: ResultSetMetaData metaData, String columnName)
204: throws SQLException {
205: for (int i = 1; i <= metaData.getColumnCount(); i++) {
206: String tmpName = metaData.getColumnLabel(i);
207: if (tmpName.equalsIgnoreCase(columnName)) {
208: return i;
209: }
210: }
211: return -1;
212: }
213:
214: public static Connection getTargetConnection(Connection conn) {
215: if (conn instanceof ConnectionProxy) {
216: return getTargetConnection(((ConnectionProxy) conn)
217: .getTargetConnection());
218: }
219: // currently a hack to suppport Spring wrapping of connections. Need to implement a nicer pluggable native extractor
220: if (springConnectionProxy != null
221: && springConnectionProxyClass != null) {
222: if (springConnectionProxyClass.isAssignableFrom(conn
223: .getClass())) {
224: try {
225: return (Connection) springConnectionProxy
226: .invoke(conn);
227: } catch (Exception e) {
228: return conn;
229: }
230: }
231: }
232: return conn;
233: }
234: }
|