001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.dbcp;
019:
020: import java.sql.Connection;
021: import java.sql.ResultSet;
022: import java.sql.SQLException;
023: import java.sql.SQLWarning;
024: import java.sql.Statement;
025: import java.util.List;
026:
027: /**
028: * A base delegating implementation of {@link Statement}.
029: * <p>
030: * All of the methods from the {@link Statement} interface
031: * simply check to see that the {@link Statement} is active,
032: * and call the corresponding method on the "delegate"
033: * provided in my constructor.
034: * <p>
035: * Extends AbandonedTrace to implement Statement tracking and
036: * logging of code which created the Statement. Tracking the
037: * Statement ensures that the Connection which created it can
038: * close any open Statement's on Connection close.
039: *
040: * @author Rodney Waldhoff
041: * @author Glenn L. Nielsen
042: * @author James House
043: * @author Dirk Verbeeck
044: * @version $Revision: 500687 $ $Date: 2007-01-27 16:33:47 -0700 (Sat, 27 Jan 2007) $
045: */
046: public class DelegatingStatement extends AbandonedTrace implements
047: Statement {
048: /** My delegate. */
049: protected Statement _stmt = null;
050: /** The connection that created me. **/
051: protected DelegatingConnection _conn = null;
052:
053: /**
054: * Create a wrapper for the Statement which traces this
055: * Statement to the Connection which created it and the
056: * code which created it.
057: *
058: * @param s the {@link Statement} to delegate all calls to.
059: * @param c the {@link DelegatingConnection} that created this statement.
060: */
061: public DelegatingStatement(DelegatingConnection c, Statement s) {
062: super (c);
063: _stmt = s;
064: _conn = c;
065: }
066:
067: /**
068: * Returns my underlying {@link Statement}.
069: * @return my underlying {@link Statement}.
070: * @see #getInnermostDelegate
071: */
072: public Statement getDelegate() {
073: return _stmt;
074: }
075:
076: public boolean equals(Object obj) {
077: Statement delegate = getInnermostDelegate();
078: if (delegate == null) {
079: return false;
080: }
081: if (obj instanceof DelegatingStatement) {
082: DelegatingStatement s = (DelegatingStatement) obj;
083: return delegate.equals(s.getInnermostDelegate());
084: } else {
085: return delegate.equals(obj);
086: }
087: }
088:
089: public int hashCode() {
090: Object obj = getInnermostDelegate();
091: if (obj == null) {
092: return 0;
093: }
094: return obj.hashCode();
095: }
096:
097: /**
098: * If my underlying {@link Statement} is not a
099: * <tt>DelegatingStatement</tt>, returns it,
100: * otherwise recursively invokes this method on
101: * my delegate.
102: * <p>
103: * Hence this method will return the first
104: * delegate that is not a <tt>DelegatingStatement</tt>
105: * or <tt>null</tt> when no non-<tt>DelegatingStatement</tt>
106: * delegate can be found by transversing this chain.
107: * <p>
108: * This method is useful when you may have nested
109: * <tt>DelegatingStatement</tt>s, and you want to make
110: * sure to obtain a "genuine" {@link Statement}.
111: * @see #getDelegate
112: */
113: public Statement getInnermostDelegate() {
114: Statement s = _stmt;
115: while (s != null && s instanceof DelegatingStatement) {
116: s = ((DelegatingStatement) s).getDelegate();
117: if (this == s) {
118: return null;
119: }
120: }
121: return s;
122: }
123:
124: /** Sets my delegate. */
125: public void setDelegate(Statement s) {
126: _stmt = s;
127: }
128:
129: protected boolean _closed = false;
130:
131: protected boolean isClosed() {
132: return _closed;
133: }
134:
135: protected void checkOpen() throws SQLException {
136: if (isClosed()) {
137: throw new SQLException(this .getClass().getName()
138: + " with address: \"" + this .toString()
139: + "\" is closed.");
140: }
141: }
142:
143: /**
144: * Close this DelegatingStatement, and close
145: * any ResultSets that were not explicitly closed.
146: */
147: public void close() throws SQLException {
148: try {
149: try {
150: if (_conn != null) {
151: _conn.removeTrace(this );
152: _conn = null;
153: }
154:
155: // The JDBC spec requires that a statment close any open
156: // ResultSet's when it is closed.
157: // FIXME The PreparedStatement we're wrapping should handle this for us.
158: // See bug 17301 for what could happen when ResultSets are closed twice.
159: List resultSets = getTrace();
160: if (resultSets != null) {
161: ResultSet[] set = (ResultSet[]) resultSets
162: .toArray(new ResultSet[resultSets.size()]);
163: for (int i = 0; i < set.length; i++) {
164: set[i].close();
165: }
166: clearTrace();
167: }
168:
169: _stmt.close();
170: } catch (SQLException e) {
171: handleException(e);
172: }
173: } finally {
174: _closed = true;
175: }
176: }
177:
178: protected void handleException(SQLException e) throws SQLException {
179: if (_conn != null) {
180: _conn.handleException(e);
181: } else {
182: throw e;
183: }
184: }
185:
186: protected void activate() throws SQLException {
187: if (_stmt instanceof DelegatingStatement) {
188: ((DelegatingStatement) _stmt).activate();
189: }
190: }
191:
192: protected void passivate() throws SQLException {
193: if (_stmt instanceof DelegatingStatement) {
194: ((DelegatingStatement) _stmt).passivate();
195: }
196: }
197:
198: public Connection getConnection() throws SQLException {
199: checkOpen();
200: return _conn; // return the delegating connection that created this
201: }
202:
203: public ResultSet executeQuery(String sql) throws SQLException {
204: checkOpen();
205: try {
206: return DelegatingResultSet.wrapResultSet(this , _stmt
207: .executeQuery(sql));
208: } catch (SQLException e) {
209: handleException(e);
210: return null;
211: }
212: }
213:
214: public ResultSet getResultSet() throws SQLException {
215: checkOpen();
216: try {
217: return DelegatingResultSet.wrapResultSet(this , _stmt
218: .getResultSet());
219: } catch (SQLException e) {
220: handleException(e);
221: return null;
222: }
223: }
224:
225: public int executeUpdate(String sql) throws SQLException {
226: checkOpen();
227: try {
228: return _stmt.executeUpdate(sql);
229: } catch (SQLException e) {
230: handleException(e);
231: return 0;
232: }
233: }
234:
235: public int getMaxFieldSize() throws SQLException {
236: checkOpen();
237: try {
238: return _stmt.getMaxFieldSize();
239: } catch (SQLException e) {
240: handleException(e);
241: return 0;
242: }
243: }
244:
245: public void setMaxFieldSize(int max) throws SQLException {
246: checkOpen();
247: try {
248: _stmt.setMaxFieldSize(max);
249: } catch (SQLException e) {
250: handleException(e);
251: }
252: }
253:
254: public int getMaxRows() throws SQLException {
255: checkOpen();
256: try {
257: return _stmt.getMaxRows();
258: } catch (SQLException e) {
259: handleException(e);
260: return 0;
261: }
262: }
263:
264: public void setMaxRows(int max) throws SQLException {
265: checkOpen();
266: try {
267: _stmt.setMaxRows(max);
268: } catch (SQLException e) {
269: handleException(e);
270: }
271: }
272:
273: public void setEscapeProcessing(boolean enable) throws SQLException {
274: checkOpen();
275: try {
276: _stmt.setEscapeProcessing(enable);
277: } catch (SQLException e) {
278: handleException(e);
279: }
280: }
281:
282: public int getQueryTimeout() throws SQLException {
283: checkOpen();
284: try {
285: return _stmt.getQueryTimeout();
286: } catch (SQLException e) {
287: handleException(e);
288: return 0;
289: }
290: }
291:
292: public void setQueryTimeout(int seconds) throws SQLException {
293: checkOpen();
294: try {
295: _stmt.setQueryTimeout(seconds);
296: } catch (SQLException e) {
297: handleException(e);
298: }
299: }
300:
301: public void cancel() throws SQLException {
302: checkOpen();
303: try {
304: _stmt.cancel();
305: } catch (SQLException e) {
306: handleException(e);
307: }
308: }
309:
310: public SQLWarning getWarnings() throws SQLException {
311: checkOpen();
312: try {
313: return _stmt.getWarnings();
314: } catch (SQLException e) {
315: handleException(e);
316: return null;
317: }
318: }
319:
320: public void clearWarnings() throws SQLException {
321: checkOpen();
322: try {
323: _stmt.clearWarnings();
324: } catch (SQLException e) {
325: handleException(e);
326: }
327: }
328:
329: public void setCursorName(String name) throws SQLException {
330: checkOpen();
331: try {
332: _stmt.setCursorName(name);
333: } catch (SQLException e) {
334: handleException(e);
335: }
336: }
337:
338: public boolean execute(String sql) throws SQLException {
339: checkOpen();
340: try {
341: return _stmt.execute(sql);
342: } catch (SQLException e) {
343: handleException(e);
344: return false;
345: }
346: }
347:
348: public int getUpdateCount() throws SQLException {
349: checkOpen();
350: try {
351: return _stmt.getUpdateCount();
352: } catch (SQLException e) {
353: handleException(e);
354: return 0;
355: }
356: }
357:
358: public boolean getMoreResults() throws SQLException {
359: checkOpen();
360: try {
361: return _stmt.getMoreResults();
362: } catch (SQLException e) {
363: handleException(e);
364: return false;
365: }
366: }
367:
368: public void setFetchDirection(int direction) throws SQLException {
369: checkOpen();
370: try {
371: _stmt.setFetchDirection(direction);
372: } catch (SQLException e) {
373: handleException(e);
374: }
375: }
376:
377: public int getFetchDirection() throws SQLException {
378: checkOpen();
379: try {
380: return _stmt.getFetchDirection();
381: } catch (SQLException e) {
382: handleException(e);
383: return 0;
384: }
385: }
386:
387: public void setFetchSize(int rows) throws SQLException {
388: checkOpen();
389: try {
390: _stmt.setFetchSize(rows);
391: } catch (SQLException e) {
392: handleException(e);
393: }
394: }
395:
396: public int getFetchSize() throws SQLException {
397: checkOpen();
398: try {
399: return _stmt.getFetchSize();
400: } catch (SQLException e) {
401: handleException(e);
402: return 0;
403: }
404: }
405:
406: public int getResultSetConcurrency() throws SQLException {
407: checkOpen();
408: try {
409: return _stmt.getResultSetConcurrency();
410: } catch (SQLException e) {
411: handleException(e);
412: return 0;
413: }
414: }
415:
416: public int getResultSetType() throws SQLException {
417: checkOpen();
418: try {
419: return _stmt.getResultSetType();
420: } catch (SQLException e) {
421: handleException(e);
422: return 0;
423: }
424: }
425:
426: public void addBatch(String sql) throws SQLException {
427: checkOpen();
428: try {
429: _stmt.addBatch(sql);
430: } catch (SQLException e) {
431: handleException(e);
432: }
433: }
434:
435: public void clearBatch() throws SQLException {
436: checkOpen();
437: try {
438: _stmt.clearBatch();
439: } catch (SQLException e) {
440: handleException(e);
441: }
442: }
443:
444: public int[] executeBatch() throws SQLException {
445: checkOpen();
446: try {
447: return _stmt.executeBatch();
448: } catch (SQLException e) {
449: handleException(e);
450: return null;
451: }
452: }
453:
454: /**
455: * Returns a String representation of this object.
456: *
457: * @return String
458: * @since 1.2.2
459: */
460: public String toString() {
461: return _stmt.toString();
462: }
463:
464: // ------------------- JDBC 3.0 -----------------------------------------
465: // Will be commented by the build process on a JDBC 2.0 system
466:
467: /* JDBC_3_ANT_KEY_BEGIN */
468:
469: public boolean getMoreResults(int current) throws SQLException {
470: checkOpen();
471: try {
472: return _stmt.getMoreResults(current);
473: } catch (SQLException e) {
474: handleException(e);
475: return false;
476: }
477: }
478:
479: public ResultSet getGeneratedKeys() throws SQLException {
480: checkOpen();
481: try {
482: return _stmt.getGeneratedKeys();
483: } catch (SQLException e) {
484: handleException(e);
485: return null;
486: }
487: }
488:
489: public int executeUpdate(String sql, int autoGeneratedKeys)
490: throws SQLException {
491: checkOpen();
492: try {
493: return _stmt.executeUpdate(sql, autoGeneratedKeys);
494: } catch (SQLException e) {
495: handleException(e);
496: return 0;
497: }
498: }
499:
500: public int executeUpdate(String sql, int columnIndexes[])
501: throws SQLException {
502: checkOpen();
503: try {
504: return _stmt.executeUpdate(sql, columnIndexes);
505: } catch (SQLException e) {
506: handleException(e);
507: return 0;
508: }
509: }
510:
511: public int executeUpdate(String sql, String columnNames[])
512: throws SQLException {
513: checkOpen();
514: try {
515: return _stmt.executeUpdate(sql, columnNames);
516: } catch (SQLException e) {
517: handleException(e);
518: return 0;
519: }
520: }
521:
522: public boolean execute(String sql, int autoGeneratedKeys)
523: throws SQLException {
524: checkOpen();
525: try {
526: return _stmt.execute(sql, autoGeneratedKeys);
527: } catch (SQLException e) {
528: handleException(e);
529: return false;
530: }
531: }
532:
533: public boolean execute(String sql, int columnIndexes[])
534: throws SQLException {
535: checkOpen();
536: try {
537: return _stmt.execute(sql, columnIndexes);
538: } catch (SQLException e) {
539: handleException(e);
540: return false;
541: }
542: }
543:
544: public boolean execute(String sql, String columnNames[])
545: throws SQLException {
546: checkOpen();
547: try {
548: return _stmt.execute(sql, columnNames);
549: } catch (SQLException e) {
550: handleException(e);
551: return false;
552: }
553: }
554:
555: public int getResultSetHoldability() throws SQLException {
556: checkOpen();
557: try {
558: return _stmt.getResultSetHoldability();
559: } catch (SQLException e) {
560: handleException(e);
561: return 0;
562: }
563: }
564:
565: /* JDBC_3_ANT_KEY_END */
566: }
|