001: package com.protomatter.jdbc.pool;
002:
003: /**
004: * {{{ The Protomatter Software License, Version 1.0
005: * derived from The Apache Software License, Version 1.1
006: *
007: * Copyright (c) 1998-2002 Nate Sammons. All rights reserved.
008: *
009: * Redistribution and use in source and binary forms, with or without
010: * modification, are permitted provided that the following conditions
011: * are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution,
022: * if any, must include the following acknowledgment:
023: * "This product includes software developed for the
024: * Protomatter Software Project
025: * (http://protomatter.sourceforge.net/)."
026: * Alternately, this acknowledgment may appear in the software itself,
027: * if and wherever such third-party acknowledgments normally appear.
028: *
029: * 4. The names "Protomatter" and "Protomatter Software Project" must
030: * not be used to endorse or promote products derived from this
031: * software without prior written permission. For written
032: * permission, please contact support@protomatter.com.
033: *
034: * 5. Products derived from this software may not be called "Protomatter",
035: * nor may "Protomatter" appear in their name, without prior written
036: * permission of the Protomatter Software Project
037: * (support@protomatter.com).
038: *
039: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
040: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
041: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
042: * DISCLAIMED. IN NO EVENT SHALL THE PROTOMATTER SOFTWARE PROJECT OR
043: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
044: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
045: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
046: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
047: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
048: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
049: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
050: * SUCH DAMAGE. }}}
051: */
052:
053: import java.io.*;
054: import java.sql.*;
055: import java.util.*;
056: import java.text.MessageFormat;
057: import com.protomatter.util.*;
058: import com.protomatter.pool.*;
059: import com.protomatter.syslog.*;
060:
061: /**
062: * A wrapper.
063: *
064: * @see java.sql.Connection
065: * @see JdbcConnectionPoolDriver
066: * @see JdbcConnectionPool
067: */
068: class ConnectionWrapper implements Connection, SyslogChannelAware {
069: private JdbcConnectionPool pool = null;
070: private JdbcConnectionPoolConnection connection = null;
071: private boolean isClosed = false;
072:
073: protected static Debug DEBUG = Debug
074: .forPackage(ConnectionWrapper.class);
075: protected static Channel log = Channel
076: .forPackage(ConnectionWrapper.class);
077:
078: ConnectionWrapper(JdbcConnectionPoolConnection connection,
079: JdbcConnectionPool pool) {
080: super ();
081: this .connection = connection;
082: this .pool = pool;
083: }
084:
085: /**
086: * Get the connection that this object wraps. This method
087: * should only be called if you <i>really</i> know what
088: * you're doing. This method exposes the connection
089: * that is actually connected to the database, but you should
090: * not really have any need to get ahold of it. This method
091: * will return <tt>null</tt> if you have called the
092: * <tt>close()</tt> method already.
093: */
094: public Connection getConnection() {
095: if (this .connection == null)
096: return null;
097: return this .connection.getConnection();
098: }
099:
100: /**
101: * Get the pool that this connection is associated with.
102: */
103: public JdbcConnectionPool getConnectionPool() {
104: return this .pool;
105: }
106:
107: /**
108: * Returns the channel information from the pool
109: * this connection is associated with.
110: */
111: public Object getSyslogChannel() {
112: return this .pool.getSyslogChannel();
113: }
114:
115: /**
116: * Invalidates this connection manually. When this connection
117: * is closed, the pool will discard it.
118: */
119: public void invalidate() {
120: if (DEBUG.debug())
121: log.debug(this , StackTraceUtil.whereAmI()
122: .getShortClassAndMethod());
123: if (this .connection != null)
124: this .connection.invalidate();
125: }
126:
127: /**
128: * Will check that this connection is working and refresh it if not.
129: * This executes the validity check statement that was set when
130: * the connection pool was created. If that statement was not set,
131: * the connection is refreshed no matter what. If the statement was
132: * set, it is executed and if an exception is generated, the connection
133: * is refreshed. If there's a problem refreshing the connection, this
134: * connection wrapper is invalidated -- you will have to either keep
135: * calling <tt>refresh()</tt> until it doesn't throw a <tt>SQLException</tt>, or just call
136: * <tt>close()</tt> and open another connection using the <tt>JdbcConnectionPoolDriver</tt>.
137: * If <tt>verbose</tt> is true, messages are written to Syslog
138: * during the refresh operation. Note that after the <tt>close()</tt>
139: * method has been called, calling this method will throw a
140: * <tt>SQLException</tt> stating that the connection is closed.
141: *
142: * @exception SQLException If the connection needs refreshing and there is
143: * a problem re-opening the connection.
144: */
145:
146: public synchronized void refresh(boolean verbose)
147: throws SQLException {
148: if (DEBUG.debug())
149: log.debug(this , StackTraceUtil.whereAmI()
150: .getShortClassAndMethod());
151: checkClosed();
152: this .connection.refresh(verbose);
153: }
154:
155: /**
156: * Performs a non-verbose refresh. This method
157: * will throw a <tt>SQLException</tt> and
158: * the connection will not be refreshed if
159: * the <tt>close()</tt> method has been called.
160: *
161: * @see #refresh(boolean)
162: */
163: public synchronized void refresh() throws SQLException {
164: refresh(false);
165: }
166:
167: private final void checkClosed() throws SQLException {
168: if (this .isClosed)
169: throw new SQLException(
170: PoolResources
171: .getResourceString(MessageConstants.CONNECTION_IS_CLOSED));
172: }
173:
174: /**
175: * @see java.sql.Connection
176: *
177: * @exception SQLException Because the underlying connection can throw one.
178: */
179: public Statement createStatement() throws SQLException {
180: checkClosed();
181: long time = System.currentTimeMillis();
182: Statement stmt = this .connection.createStatement();
183: time = System.currentTimeMillis() - time;
184: if (DEBUG.debug()) {
185: log.debug(this , StackTraceUtil.whereAmI()
186: .getShortClassAndMethod()
187: + " took " + time + "ms");
188: return new StatementWrapper(this , stmt);
189: }
190: return stmt;
191: }
192:
193: /**
194: * @see java.sql.Connection
195: *
196: * @exception SQLException Because the underlying connection can throw one.
197: */
198: public PreparedStatement prepareStatement(String sql)
199: throws SQLException {
200: checkClosed();
201: long time = System.currentTimeMillis();
202: PreparedStatement stmt = this .connection.prepareStatement(sql);
203: time = System.currentTimeMillis() - time;
204: if (DEBUG.debug()) {
205: log.debug(this , StackTraceUtil.whereAmI()
206: .getShortClassAndMethod()
207: + " SQL=\"" + sql + "\" took " + time + "ms");
208: return new PreparedStatementWrapper(this , stmt);
209: }
210: return stmt;
211: }
212:
213: /**
214: * @see java.sql.Connection
215: *
216: * @exception SQLException Because the underlying connection can throw one.
217: */
218: public CallableStatement prepareCall(String sql)
219: throws SQLException {
220: checkClosed();
221: long time = System.currentTimeMillis();
222: CallableStatement stmt = this .connection.prepareCall(sql);
223: time = System.currentTimeMillis() - time;
224: if (DEBUG.debug()) {
225: log.debug(this , StackTraceUtil.whereAmI()
226: .getShortClassAndMethod()
227: + " SQL=\"" + sql + "\" took " + time + "ms");
228: return new CallableStatementWrapper(this , stmt);
229: }
230: return stmt;
231: }
232:
233: /**
234: * @see java.sql.Connection
235: *
236: * @exception SQLException Because the underlying connection can throw one.
237: */
238: public String nativeSQL(String sql) throws SQLException {
239: checkClosed();
240: long time = System.currentTimeMillis();
241: String nsql = this .connection.nativeSQL(sql);
242: time = System.currentTimeMillis() - time;
243: if (DEBUG.debug())
244: log.debug(this , StackTraceUtil.whereAmI()
245: .getShortClassAndMethod()
246: + " SQL=\""
247: + sql
248: + "\" NativeSQL=\""
249: + nsql
250: + "\" took " + time + "ms");
251: return nsql;
252: }
253:
254: /**
255: * @see java.sql.Connection
256: *
257: * @exception SQLException Because the underlying connection can throw one.
258: */
259: public void setAutoCommit(boolean autoCommit) throws SQLException {
260: if (DEBUG.debug())
261: log.debug(this , StackTraceUtil.whereAmI()
262: .getShortClassAndMethod()
263: + " AutoCommit=\"" + autoCommit + "\"");
264: checkClosed();
265: this .connection.setAutoCommit(autoCommit);
266: }
267:
268: /**
269: * @see java.sql.Connection
270: *
271: * @exception SQLException Because the underlying connection can throw one.
272: */
273: public boolean getAutoCommit() throws SQLException {
274: checkClosed();
275: return this .connection.getAutoCommit();
276: }
277:
278: /**
279: * @see java.sql.Connection
280: *
281: * @exception SQLException Because the underlying connection can throw one.
282: */
283: public void commit() throws SQLException {
284: if (DEBUG.debug())
285: log.debug(this , StackTraceUtil.whereAmI()
286: .getShortClassAndMethod());
287: checkClosed();
288: this .connection.commit();
289: }
290:
291: /**
292: * @see java.sql.Connection
293: *
294: * @exception SQLException Because the underlying connection can throw one.
295: */
296: public void rollback() throws SQLException {
297: if (DEBUG.debug())
298: log.debug(this , StackTraceUtil.whereAmI()
299: .getShortClassAndMethod());
300: checkClosed();
301: this .connection.rollback();
302: }
303:
304: /**
305: * Close the connection. The underlying connection is checked
306: * back into the pool so it can be used by someone else. If this
307: * method completes without throwing a
308: * <tt>SQLException</tt>, then calling any method on this class
309: * (except this <tt>close()</tt> method) will throw a
310: * <tt>SQLException</tt> stating that the connection is closed.
311: * Repeatedly calling this method has no effect and will not
312: * throw exceptions (which some JDBC drivers do).
313: *
314: * @see java.sql.Connection
315: *
316: * @exception SQLException Because the underlying connection can throw one.
317: */
318: public void close() throws SQLException {
319: if (DEBUG.debug())
320: log.debug(this , StackTraceUtil.whereAmI()
321: .getShortClassAndMethod());
322: if (this .isClosed)
323: return;
324:
325: this .connection.close();
326: this .isClosed = true;
327: this .connection = null;
328: }
329:
330: /**
331: * @see java.sql.Connection
332: *
333: * @exception SQLException Because the underlying connection can throw one.
334: */
335: public boolean isClosed() throws SQLException {
336: // since we don't really close the this.connection, we need to
337: // tell the if they think the closed it ;-)
338: return this .isClosed;
339: }
340:
341: /**
342: * @see java.sql.Connection
343: *
344: * @exception SQLException Because the underlying connection can throw one.
345: */
346: public DatabaseMetaData getMetaData() throws SQLException {
347: checkClosed();
348: return this .connection.getMetaData();
349: }
350:
351: /**
352: * @see java.sql.Connection
353: *
354: * @exception SQLException Because the underlying connection can throw one.
355: */
356: public void setReadOnly(boolean readOnly) throws SQLException {
357: if (DEBUG.debug())
358: log.debug(this , StackTraceUtil.whereAmI()
359: .getShortClassAndMethod()
360: + " ReadOnly=\"" + readOnly + "\"");
361: checkClosed();
362: this .connection.setReadOnly(readOnly);
363: }
364:
365: /**
366: * @see java.sql.Connection
367: *
368: * @exception SQLException Because the underlying connection can throw one.
369: */
370: public boolean isReadOnly() throws SQLException {
371: checkClosed();
372: return this .connection.isReadOnly();
373: }
374:
375: /**
376: * @see java.sql.Connection
377: *
378: * @exception SQLException Because the underlying connection can throw one.
379: */
380: public void setCatalog(String catalog) throws SQLException {
381: if (DEBUG.debug())
382: log.debug(this , StackTraceUtil.whereAmI()
383: .getShortClassAndMethod()
384: + " Catalog=\"" + catalog + "\"");
385: checkClosed();
386: this .connection.setCatalog(catalog);
387: }
388:
389: /**
390: * @see java.sql.Connection
391: *
392: * @exception SQLException Because the underlying connection can throw one.
393: */
394: public String getCatalog() throws SQLException {
395: checkClosed();
396: return this .connection.getCatalog();
397: }
398:
399: /**
400: * @see java.sql.Connection
401: *
402: * @exception SQLException Because the underlying connection can throw one.
403: */
404: public void setTransactionIsolation(int level) throws SQLException {
405: if (DEBUG.debug())
406: log.debug(this , StackTraceUtil.whereAmI()
407: .getShortClassAndMethod()
408: + " IsolationLevel=\"" + level + "\"");
409: checkClosed();
410: this .connection.setTransactionIsolation(level);
411: }
412:
413: /**
414: * @see java.sql.Connection
415: *
416: * @exception SQLException Because the underlying connection can throw one.
417: */
418: public int getTransactionIsolation() throws SQLException {
419: checkClosed();
420: return this .connection.getTransactionIsolation();
421: }
422:
423: /**
424: * @see java.sql.Connection
425: *
426: * @exception SQLException Because the underlying connection can throw one.
427: */
428: public SQLWarning getWarnings() throws SQLException {
429: checkClosed();
430: return this .connection.getWarnings();
431: }
432:
433: /**
434: * @see java.sql.Connection
435: *
436: * @exception SQLException Because the underlying connection can throw one.
437: */
438: public void clearWarnings() throws SQLException {
439: if (DEBUG.debug())
440: log.debug(this , StackTraceUtil.whereAmI()
441: .getShortClassAndMethod());
442: checkClosed();
443: this .connection.clearWarnings();
444: }
445:
446: /**
447: * @see java.sql.Connection
448: *
449: * @exception SQLException Because the underlying connection can throw one.
450: */
451: public Statement createStatement(int resultSetType,
452: int resultSetConcurrency) throws SQLException {
453: checkClosed();
454: long time = System.currentTimeMillis();
455: Statement stmt = this .connection.createStatement(resultSetType,
456: resultSetConcurrency);
457: time = System.currentTimeMillis() - time;
458: if (DEBUG.debug()) {
459: log.debug(this , StackTraceUtil.whereAmI()
460: .getShortClassAndMethod()
461: + " Type=\""
462: + resultSetType
463: + "\" Concurrency=\""
464: + resultSetConcurrency + "\" took " + time + "ms");
465: return new StatementWrapper(this , stmt);
466: }
467: return stmt;
468: }
469:
470: /**
471: * @see java.sql.Connection
472: *
473: * @exception SQLException Because the underlying connection can throw one.
474: */
475: public Map getTypeMap() throws SQLException {
476: checkClosed();
477: return this .connection.getTypeMap();
478: }
479:
480: /**
481: * @see java.sql.Connection
482: *
483: * @exception SQLException Because the underlying connection can throw one.
484: */
485: public CallableStatement prepareCall(String sql, int resultSetType,
486: int resultSetConcurrency) throws SQLException {
487: checkClosed();
488:
489: long time = System.currentTimeMillis();
490: CallableStatement stmt = this .connection.prepareCall(sql,
491: resultSetType, resultSetConcurrency);
492: time = System.currentTimeMillis() - time;
493: if (DEBUG.debug()) {
494: log.debug(this , StackTraceUtil.whereAmI()
495: .getShortClassAndMethod()
496: + " SQL=\""
497: + sql
498: + "\" Type=\""
499: + resultSetType
500: + "\" Concurrency=\""
501: + resultSetConcurrency
502: + "\" took " + time + "ms");
503: return new CallableStatementWrapper(this , stmt);
504: }
505: return stmt;
506: }
507:
508: /**
509: * @see java.sql.Connection
510: *
511: * @exception SQLException Because the underlying connection can throw one.
512: */
513: public PreparedStatement prepareStatement(String sql,
514: int resultSetType, int resultSetConcurrency)
515: throws SQLException {
516: checkClosed();
517:
518: long time = System.currentTimeMillis();
519: PreparedStatement stmt = this .connection.prepareStatement(sql,
520: resultSetType, resultSetConcurrency);
521: time = System.currentTimeMillis() - time;
522: if (DEBUG.debug()) {
523: log.debug(this , StackTraceUtil.whereAmI()
524: .getShortClassAndMethod()
525: + " SQL=\""
526: + sql
527: + "\" Type=\""
528: + resultSetType
529: + "\" Concurrency=\""
530: + resultSetConcurrency
531: + "\" took " + time + "ms");
532: return new PreparedStatementWrapper(this , stmt);
533: }
534: return stmt;
535: }
536:
537: /**
538: * @see java.sql.Connection
539: *
540: * @exception SQLException Because the underlying connection can throw one.
541: */
542: public void setTypeMap(Map typeMap) throws SQLException {
543: if (DEBUG.debug())
544: log.debug(this , StackTraceUtil.whereAmI()
545: .getShortClassAndMethod()
546: + " TypeMap=\"" + typeMap + "\"");
547: checkClosed();
548: this.connection.setTypeMap(typeMap);
549: }
550: }
|