001: /**
002: * Library name : Primrose - A Java Database Connection Pool.
003: * Published by Ben Keeping, http://primrose.org.uk .
004: * Copyright (C) 2004 Ben Keeping, primrose.org.uk
005: * Email: Use "Contact Us Form" on website
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */package uk.org.primrose.pool.core;
021:
022: import java.sql.*;
023: import uk.org.primrose.*;
024:
025: public class PoolConnection implements Connection {
026: private Connection conn = null;
027: private ConnectionHolder connHolder = null;
028:
029: protected PoolConnection(Connection conn,
030: ConnectionHolder connHolder) {
031: this .conn = conn;
032: this .connHolder = connHolder;
033: }
034:
035: /**
036: * Check for and close any unclosed result sets
037: */
038: private void checkAndCloseResultSets() {
039: // Check the resultsets are all closed
040: if (connHolder.resultsetObjects.size() > 0) {
041: try {
042: throw new Exception();
043: } catch (Exception e) {
044: StackTraceElement[] els = e.getStackTrace();
045: StringBuffer stack = new StringBuffer();
046: for (StackTraceElement el : els) {
047: stack.append("\t");
048: stack.append(el.toString());
049: stack.append("\n");
050: }
051: String message = "[PoolConnection@" + this .hashCode()
052: + "@" + connHolder.poolName
053: + "] close() : Got "
054: + connHolder.resultsetObjects.size()
055: + " unclosed ResultSets !\n" + stack.toString();
056: connHolder.logger.email(Constants.UNCLOSED_EVENT,
057: message);
058: connHolder.logger.error(message);
059:
060: }
061: while (!connHolder.resultsetObjects.empty()) {
062: PoolResultSet rs = connHolder.resultsetObjects.pop();
063: connHolder.logger.error("[PoolConnection@"
064: + this .hashCode() + "@" + connHolder.poolName
065: + "] close() : ResultSet@" + rs.hashCode()
066: + " used but not closed (I'm closing it)");
067: try {
068: rs.closeNoPop();
069: } catch (SQLException sqle) {
070: connHolder.logger.printStackTrace(sqle);
071: }
072: }
073: }
074: }
075:
076: /**
077: * Check for and close any unclosed statements
078: */
079: private void checkAndCloseStatements() {
080: // Check the statements are all closed
081: if (connHolder.statementObjects.size() > 0) {
082: try {
083: throw new Exception();
084: } catch (Exception e) {
085: StackTraceElement[] els = e.getStackTrace();
086: StringBuffer stack = new StringBuffer();
087: for (StackTraceElement el : els) {
088: stack.append("\t");
089: stack.append(el.toString());
090: stack.append("\n");
091: }
092: String message = "[PoolConnection@" + this .hashCode()
093: + "@" + connHolder.poolName
094: + "] close() : Got "
095: + connHolder.statementObjects.size()
096: + " unclosed [Callable/Prepared]Statements !\n"
097: + stack.toString();
098: connHolder.logger.email(Constants.UNCLOSED_EVENT,
099: message);
100: connHolder.logger.error(message);
101: }
102: while (!connHolder.statementObjects.empty()) {
103: PoolStatement s = connHolder.statementObjects.pop();
104: connHolder.logger.error("[PoolConnection@"
105: + this .hashCode() + "@" + connHolder.poolName
106: + "] close() : [Callable/Prepared]Statement@"
107: + s.hashCode()
108: + " used but not closed (I'm closing it)");
109: try {
110: s.closeNoPop();
111: } catch (SQLException sqle) {
112: connHolder.logger.printStackTrace(sqle);
113: }
114: }
115: }
116:
117: }
118:
119: public void close() {
120: if (DebugLogger.getEnabled())
121: DebugLogger.log("[PoolConnection@" + this .hashCode() + "@"
122: + connHolder.poolName + "] close() called ...");
123:
124: //synchronized(connHolder.lock) {
125:
126: // Check and close down any unclosed statements/cursors
127: checkAndCloseStatements();
128: checkAndCloseResultSets();
129:
130: // Check for more than one closes on this ...
131: if ((connHolder.numberOfCloses + 1) > connHolder.numberOfOpens) {
132: connHolder.logger
133: .verbose("[PoolConnection@"
134: + this .hashCode()
135: + "@"
136: + connHolder.poolName
137: + "] close() called twice - this could have serious implications on your pooling ...");
138:
139: return;
140: }
141:
142: // set some info for the log
143: connHolder.numberOfCloses++;
144: connHolder.lastUsedTimestamp = System.currentTimeMillis();
145: connHolder.lastSql = connHolder.sql;
146: connHolder.lastSqlTook = (System.currentTimeMillis() - connHolder.connOpenedDate);
147:
148: // If when called, we should just close the real connection
149: // then do so, else set the status to inactive
150: if (connHolder.closeBehaviour == Pool.ON_CLOSE_SHOULD_DIE) {
151: connHolder.myPool.connections.remove(connHolder);
152: try {
153: if (DebugLogger.getEnabled())
154: DebugLogger
155: .log("[PoolConnection@"
156: + this .hashCode()
157: + "@"
158: + connHolder.poolName
159: + "] close() closing physical connection (Pool.ON_CLOSE_SHOULD_DIE=true)");
160: this .closePhysical();
161: connHolder.sql = "connection_dumped";
162: connHolder.status = Pool.CONNECTION_DUMPED;
163: } catch (SQLException e) {
164: connHolder.logger.printStackTrace(e);
165: }
166: } else {
167: connHolder.sql = "none";
168: connHolder.connOpenedDate = 0L;
169: connHolder.status = Pool.CONNECTION_INACTIVE;
170: }
171: //}
172: connHolder.logger.verbose("[Pool@" + connHolder.poolName
173: + ",id=" + connHolder.id
174: + "] close() on conn hashcode "
175: + connHolder.conn.hashCode() + ", SQL(took "
176: + connHolder.lastSqlTook + " ms) : "
177: + connHolder.lastSql);
178:
179: if (DebugLogger.getEnabled())
180: DebugLogger.log("[PoolConnection@" + this .hashCode() + "@"
181: + connHolder.poolName + "] close() leaving ...");
182:
183: }
184:
185: /**
186: * Execute some SQL to check if the connection is OK (if user configured pool to do this)
187: * @param checkSQL
188: * @return true for OK, false for broken
189: */
190: protected boolean runCheckSQL(String checkSQL) {
191: Statement s = null;
192: ResultSet rs = null;
193: try {
194: s = conn.createStatement();
195: rs = s.executeQuery(checkSQL);
196: if (!conn.getAutoCommit())
197: conn.commit();
198: } catch (Exception e) {
199: connHolder.logger.printStackTrace(e);
200: connHolder.logger
201: .error("[Pool@"
202: + connHolder.poolName
203: + "] checkIfConnectionIsValid() : SQL Check failed.");
204: return false;
205: } finally {
206: try {
207: if (rs != null)
208: rs.close();
209: if (s != null)
210: s.close();
211: } catch (SQLException sqle) {/*don't care*/
212: }
213: }
214: return true;
215: }
216:
217: /**
218: * Close the underlying connection
219: * @throws SQLException
220: */
221: protected void closePhysical() throws SQLException {
222: this .conn.close();
223: }
224:
225: /**
226: * Get the real underlying connection (as created by your driver).
227: * Only ever use this if you are using a non-JDBC standard driver method.
228: * And be very careful when using it. Make sure you close the pool connection - not the real one
229: * Eg :
230: *
231: * // Get a pooled connection from primrose
232: * Connection poolconn = getConnection(Constants.DB_POOL_NAME);
233: *
234: * // Get a real connection from it
235: * // Do NOT close the real connection - close the pooled one (c)
236: * Connection rc = ((uk.org.primrose.pool.core.PoolConnection)poolconn).getRealConnection();
237: *
238: * // Do some stuff
239: *
240: * // Close the pooled connection
241: * poolconn.close();
242: *
243: */
244: public Connection getRealConnection() {
245: return conn;
246: }
247:
248: public Statement createStatement() throws SQLException {
249: connHolder.numberOfJDBCStatementsRun++;
250: PoolStatement ps = new PoolStatement(conn.createStatement(),
251: connHolder);
252: return ps;
253:
254: }
255:
256: public PreparedStatement prepareStatement(String sql)
257: throws SQLException {
258: connHolder.numberOfJDBCPreparedStatementsRun++;
259: PoolPreparedStatement pps = new PoolPreparedStatement(conn
260: .prepareStatement(sql), connHolder);
261: this .connHolder.sql = sql;
262: return pps;
263: }
264:
265: public CallableStatement prepareCall(String sql)
266: throws SQLException {
267: connHolder.numberOfJDBCStatementsRun++;
268: PoolCallableStatement pcs = new PoolCallableStatement(conn
269: .prepareCall(sql), connHolder);
270: this .connHolder.sql = sql;
271: return pcs;
272: }
273:
274: public String nativeSQL(String sql) throws SQLException {
275: this .connHolder.sql = sql;
276: return conn.nativeSQL(sql);
277: }
278:
279: public void setAutoCommit(boolean autoCommit) throws SQLException {
280: conn.setAutoCommit(autoCommit);
281: }
282:
283: public boolean getAutoCommit() throws SQLException {
284: return conn.getAutoCommit();
285: }
286:
287: public void commit() throws SQLException {
288: conn.commit();
289: }
290:
291: public void rollback() throws SQLException {
292: conn.rollback();
293: }
294:
295: public boolean isClosed() {
296: if (conn == null)
297: return false;
298: try {
299: return conn.isClosed();
300: } catch (SQLException sqle) {
301: sqle.printStackTrace(System.err);
302: return true;
303: }
304: }
305:
306: public DatabaseMetaData getMetaData() throws SQLException {
307: return conn.getMetaData();
308: }
309:
310: public void setReadOnly(boolean readOnly) throws SQLException {
311: conn.setReadOnly(readOnly);
312: }
313:
314: public boolean isReadOnly() throws SQLException {
315: return conn.isReadOnly();
316: }
317:
318: public void setCatalog(String catalog) throws SQLException {
319: conn.setCatalog(catalog);
320: }
321:
322: public String getCatalog() throws SQLException {
323: return conn.getCatalog();
324: }
325:
326: public void setTransactionIsolation(int level) throws SQLException {
327: conn.setTransactionIsolation(level);
328: }
329:
330: public int getTransactionIsolation() throws SQLException {
331: return conn.getTransactionIsolation();
332: }
333:
334: public SQLWarning getWarnings() throws SQLException {
335: return conn.getWarnings();
336: }
337:
338: public void clearWarnings() throws SQLException {
339: conn.clearWarnings();
340: }
341:
342: public Statement createStatement(int resultSetType,
343: int resultSetConcurrency) throws SQLException {
344: connHolder.numberOfJDBCPreparedStatementsRun++;
345: PoolStatement ps = new PoolStatement(conn.createStatement(
346: resultSetType, resultSetConcurrency), connHolder);
347: this .connHolder.sql = "";
348: return ps;
349: }
350:
351: public PreparedStatement prepareStatement(String sql,
352: int resultSetType, int resultSetConcurrency)
353: throws SQLException {
354: connHolder.numberOfJDBCPreparedStatementsRun++;
355: PoolPreparedStatement pps = new PoolPreparedStatement(conn
356: .prepareStatement(sql, resultSetType,
357: resultSetConcurrency), connHolder);
358: this .connHolder.sql = sql;
359: return pps;
360: }
361:
362: public CallableStatement prepareCall(String sql, int resultSetType,
363: int resultSetConcurrency) throws SQLException {
364: connHolder.numberOfJDBCCallableStatementsRun++;
365: PoolCallableStatement pcs = new PoolCallableStatement(conn
366: .prepareCall(sql, resultSetType, resultSetConcurrency),
367: connHolder);
368: this .connHolder.sql = sql;
369: return pcs;
370: }
371:
372: public java.util.Map<String, Class<?>> getTypeMap()
373: throws SQLException {
374: return conn.getTypeMap();
375: }
376:
377: public void setTypeMap(java.util.Map<String, Class<?>> map)
378: throws SQLException {
379: conn.setTypeMap(map);
380: }
381:
382: public void setHoldability(int holdability) throws SQLException {
383: conn.setHoldability(holdability);
384: }
385:
386: public int getHoldability() throws SQLException {
387: return conn.getHoldability();
388: }
389:
390: public Savepoint setSavepoint() throws SQLException {
391: return conn.setSavepoint();
392: }
393:
394: public Savepoint setSavepoint(String name) throws SQLException {
395: return conn.setSavepoint(name);
396: }
397:
398: public void rollback(Savepoint savepoint) throws SQLException {
399: conn.rollback(savepoint);
400: }
401:
402: public void releaseSavepoint(Savepoint savepoint)
403: throws SQLException {
404: conn.releaseSavepoint(savepoint);
405: }
406:
407: public Statement createStatement(int resultSetType,
408: int resultSetConcurrency, int resultSetHoldability)
409: throws SQLException {
410: connHolder.numberOfJDBCStatementsRun++;
411: PoolStatement ps = new PoolStatement(conn.createStatement(
412: resultSetType, resultSetConcurrency,
413: resultSetHoldability), connHolder);
414: return ps;
415:
416: }
417:
418: public PreparedStatement prepareStatement(String sql,
419: int resultSetType, int resultSetConcurrency,
420: int resultSetHoldability) throws SQLException {
421: connHolder.numberOfJDBCPreparedStatementsRun++;
422: PoolPreparedStatement pps = new PoolPreparedStatement(conn
423: .prepareStatement(sql, resultSetType,
424: resultSetConcurrency, resultSetHoldability),
425: connHolder);
426: this .connHolder.sql = sql;
427: return pps;
428: }
429:
430: public CallableStatement prepareCall(String sql, int resultSetType,
431: int resultSetConcurrency, int resultSetHoldability)
432: throws SQLException {
433: connHolder.numberOfJDBCCallableStatementsRun++;
434: PoolCallableStatement pcs = new PoolCallableStatement(conn
435: .prepareCall(sql, resultSetType, resultSetConcurrency,
436: resultSetHoldability), connHolder);
437: this .connHolder.sql = sql;
438: return pcs;
439: }
440:
441: public PreparedStatement prepareStatement(String sql,
442: int autoGeneratedKeys) throws SQLException {
443: connHolder.numberOfJDBCPreparedStatementsRun++;
444: PoolPreparedStatement pps = new PoolPreparedStatement(conn
445: .prepareStatement(sql, autoGeneratedKeys), connHolder);
446: this .connHolder.sql = sql;
447: return pps;
448:
449: }
450:
451: public PreparedStatement prepareStatement(String sql,
452: int columnIndexes[]) throws SQLException {
453: connHolder.numberOfJDBCPreparedStatementsRun++;
454: PoolPreparedStatement pps = new PoolPreparedStatement(conn
455: .prepareStatement(sql, columnIndexes), connHolder);
456: this .connHolder.sql = sql;
457: return pps;
458: }
459:
460: public PreparedStatement prepareStatement(String sql,
461: String columnNames[]) throws SQLException {
462: connHolder.numberOfJDBCPreparedStatementsRun++;
463: PoolPreparedStatement pps = new PoolPreparedStatement(conn
464: .prepareStatement(sql, columnNames), connHolder);
465: this.connHolder.sql = sql;
466: return pps;
467: }
468: }
|