001: /****************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one *
003: * or more contributor license agreements. See the NOTICE file *
004: * distributed with this work for additional information *
005: * regarding copyright ownership. The ASF licenses this file *
006: * to you under the Apache License, Version 2.0 (the *
007: * "License"); you may not use this file except in compliance *
008: * with the License. You may obtain a copy of the License at *
009: * *
010: * http://www.apache.org/licenses/LICENSE-2.0 *
011: * *
012: * Unless required by applicable law or agreed to in writing, *
013: * software distributed under the License is distributed on an *
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015: * KIND, either express or implied. See the License for the *
016: * specific language governing permissions and limitations *
017: * under the License. *
018: ****************************************************************/package org.apache.james.util.mordred;
019:
020: import java.io.PrintWriter;
021: import java.io.StringWriter;
022: import java.sql.CallableStatement;
023: import java.sql.Connection;
024: import java.sql.DatabaseMetaData;
025: import java.sql.PreparedStatement;
026: import java.sql.SQLException;
027: import java.sql.SQLWarning;
028: import java.sql.Statement;
029: import java.util.Map;
030:
031: /**
032: * An entry in a connection pool.
033: *
034: */
035: public class PoolConnEntry implements java.sql.Connection {
036: private static final boolean DEEP_DEBUG = false;
037:
038: // States for connections (in use, being tested, or active)
039: public final static int AVAILABLE = 0;
040: public final static int ACTIVE = 1;
041:
042: private JdbcDataSource container;
043:
044: private Connection connection;
045: private int status;
046: private long lockTime;
047: private long createDate;
048: private long lastActivity;
049: private int id;
050: private java.lang.Throwable trace;
051:
052: /**
053: * Insert the method's description here.
054: * Creation date: (8/24/99 11:43:45 AM)
055: * @param conn java.sql.Connection
056: */
057: public PoolConnEntry(JdbcDataSource container, Connection conn,
058: int id) {
059: this .container = container;
060: this .connection = conn;
061: status = AVAILABLE;
062: createDate = System.currentTimeMillis();
063: lastActivity = System.currentTimeMillis();
064: this .id = id;
065: }
066:
067: /**
068: * Locks an entry for anybody else using it
069: */
070: public synchronized boolean lock() throws SQLException {
071: if (DEEP_DEBUG) {
072: System.out.println("Trying to lock");
073: }
074:
075: if (status != PoolConnEntry.AVAILABLE) {
076: return false;
077: }
078:
079: if (DEEP_DEBUG) {
080: System.out.println("Available");
081: }
082:
083: if (false) {
084: //There really is no sense in doing this...
085: // maybe make it a conf option at some point, but really slows
086: // down the pooling.
087: if (connection.isClosed()) {
088: throw new SQLException("Connection has been closed.");
089: }
090:
091: if (DEEP_DEBUG) {
092: System.out.println("not closed");
093: }
094: }
095:
096: status = PoolConnEntry.ACTIVE;
097: lockTime = System.currentTimeMillis();
098: lastActivity = lockTime;
099: trace = new Throwable();
100: clearWarnings();
101: if (DEEP_DEBUG) {
102: System.out.println("Returning");
103: }
104: return true;
105: }
106:
107: /**
108: * Resets flags on an entry for reuse in the pool
109: */
110: public synchronized void unlock() {
111: lastActivity = System.currentTimeMillis();
112: trace = null;
113: status = AVAILABLE;
114: }
115:
116: /**
117: * Simple method to log any warnings on an entry (connection), and
118: * then clear them.
119: * @throws java.sql.SQLException
120: */
121: public void clearWarnings() {
122: try {
123: SQLWarning currSQLWarning = connection.getWarnings();
124: while (currSQLWarning != null) {
125: StringBuffer logBuffer = new StringBuffer(256).append(
126: "Warnings on connection ").append(id).append(
127: currSQLWarning);
128: container.debug(logBuffer.toString());
129: currSQLWarning = currSQLWarning.getNextWarning();
130: }
131: connection.clearWarnings();
132: } catch (SQLException sqle) {
133: container.debug("Error while clearing exceptions on " + id);
134: // It will probably get killed by itself before too long if this failed
135: }
136: }
137:
138: /**
139: * Insert the method's description here.
140: * Creation date: (8/24/99 11:43:19 AM)
141: * @return a long representing the time this entry was created
142: */
143: public long getCreateDate() {
144: return createDate;
145: }
146:
147: /**
148: * Insert the method's description here.
149: * Creation date: (8/24/99 12:09:01 PM)
150: * @return int
151: */
152: public int getId() {
153: return id;
154: }
155:
156: /**
157: * Insert the method's description here.
158: * Creation date: (8/24/99 11:43:19 AM)
159: * @return long
160: */
161: public long getLastActivity() {
162: return lastActivity;
163: }
164:
165: /**
166: * Insert the method's description here.
167: * Creation date: (8/24/99 11:43:19 AM)
168: * @return long
169: */
170: public long getLockTime() {
171: return lockTime;
172: }
173:
174: /**
175: * Insert the method's description here.
176: * Creation date: (8/24/99 11:43:19 AM)
177: * @return int
178: */
179: public int getStatus() {
180: return status;
181: }
182:
183: /**
184: * Insert the method's description here.
185: * Creation date: (8/24/99 2:33:38 PM)
186: * @return java.lang.Throwable
187: */
188: public java.lang.Throwable getTrace() {
189: return trace;
190: }
191:
192: /**
193: * Need to clean up the connection
194: */
195: protected void finalize() {
196: container.debug("Closing connection " + id);
197: try {
198: connection.close();
199: } catch (SQLException ex) {
200: StringBuffer warnBuffer = new StringBuffer(64).append(
201: "Cannot close connection ").append(id).append(
202: " on finalize");
203: container.warn(warnBuffer.toString());
204: }
205: // Dump the stack trace of whoever created this connection
206: if (getTrace() != null) {
207: StringWriter sout = new StringWriter();
208: trace.printStackTrace(new PrintWriter(sout, true));
209: container.info(sout.toString());
210: }
211: }
212:
213: public String getString() {
214: StringBuffer poolConnStringBuffer = new StringBuffer(64)
215: .append(getId()).append(": ").append(
216: connection.toString());
217: return poolConnStringBuffer.toString();
218: }
219:
220: /*
221: * New approach now actually has this implement a connection, as a wrapper.
222: * All calls will be passed to underlying connection.
223: * Except when closed is called, which will instead cause the releaseConnection on
224: * the parent to be executed.
225: *
226: * These are the methods from java.sql.Connection
227: */
228:
229: public void close() throws SQLException {
230: clearWarnings();
231: container.releaseConnection(this );
232: }
233:
234: /**
235: * Returns whether this entry is closed.
236: *
237: * @return whether the underlying conntection is closed
238: */
239: public boolean isClosed() throws SQLException {
240: return connection.isClosed();
241: }
242:
243: public final Statement createStatement() throws SQLException {
244: return connection.createStatement();
245: }
246:
247: public final PreparedStatement prepareStatement(final String sql)
248: throws SQLException {
249: return connection.prepareStatement(sql);
250: }
251:
252: public final CallableStatement prepareCall(final String sql)
253: throws SQLException {
254: return connection.prepareCall(sql);
255: }
256:
257: public final String nativeSQL(final String sql) throws SQLException {
258: return connection.nativeSQL(sql);
259: }
260:
261: public final void setAutoCommit(final boolean autoCommit)
262: throws SQLException {
263: connection.setAutoCommit(autoCommit);
264: }
265:
266: public final boolean getAutoCommit() throws SQLException {
267: return connection.getAutoCommit();
268: }
269:
270: public final void commit() throws SQLException {
271: connection.commit();
272: }
273:
274: public final void rollback() throws SQLException {
275: connection.rollback();
276: }
277:
278: public final DatabaseMetaData getMetaData() throws SQLException {
279: return connection.getMetaData();
280: }
281:
282: public final void setReadOnly(final boolean readOnly)
283: throws SQLException {
284: connection.setReadOnly(readOnly);
285: }
286:
287: public final boolean isReadOnly() throws SQLException {
288: return connection.isReadOnly();
289: }
290:
291: public final void setCatalog(final String catalog)
292: throws SQLException {
293: connection.setCatalog(catalog);
294: }
295:
296: public final String getCatalog() throws SQLException {
297: return connection.getCatalog();
298: }
299:
300: public final void setTransactionIsolation(final int level)
301: throws SQLException {
302: connection.setTransactionIsolation(level);
303: }
304:
305: public final int getTransactionIsolation() throws SQLException {
306: return connection.getTransactionIsolation();
307: }
308:
309: public final SQLWarning getWarnings() throws SQLException {
310: return connection.getWarnings();
311: }
312:
313: public final Statement createStatement(final int resultSetType,
314: final int resultSetConcurrency) throws SQLException {
315: return connection.createStatement(resultSetType,
316: resultSetConcurrency);
317: }
318:
319: public final PreparedStatement prepareStatement(final String sql,
320: final int resultSetType, final int resultSetConcurrency)
321: throws SQLException {
322: return connection.prepareStatement(sql, resultSetType,
323: resultSetConcurrency);
324: }
325:
326: public final CallableStatement prepareCall(final String sql,
327: final int resultSetType, final int resultSetConcurrency)
328: throws SQLException {
329: return connection.prepareCall(sql, resultSetType,
330: resultSetConcurrency);
331: }
332:
333: public final Map getTypeMap() throws SQLException {
334: return connection.getTypeMap();
335: }
336:
337: public final void setTypeMap(final Map map) throws SQLException {
338: connection.setTypeMap(map);
339: }
340:
341: /*-- JDBC_3_ANT_KEY */
342: public final void setHoldability(int holdability)
343: throws SQLException {
344: throw new SQLException(
345: "This is not a Jdbc 3.0 Compliant Connection");
346: }
347:
348: public final int getHoldability() throws SQLException {
349: throw new SQLException(
350: "This is not a Jdbc 3.0 Compliant Connection");
351: }
352:
353: public final java.sql.Savepoint setSavepoint() throws SQLException {
354: throw new SQLException(
355: "This is not a Jdbc 3.0 Compliant Connection");
356: }
357:
358: public final java.sql.Savepoint setSavepoint(String savepoint)
359: throws SQLException {
360: throw new SQLException(
361: "This is not a Jdbc 3.0 Compliant Connection");
362: }
363:
364: public final void rollback(java.sql.Savepoint savepoint)
365: throws SQLException {
366: throw new SQLException(
367: "This is not a Jdbc 3.0 Compliant Connection");
368: }
369:
370: public final void releaseSavepoint(java.sql.Savepoint savepoint)
371: throws SQLException {
372: throw new SQLException(
373: "This is not a Jdbc 3.0 Compliant Connection");
374: }
375:
376: public final Statement createStatement(int resulSetType,
377: int resultSetConcurrency, int resultSetHoldability)
378: throws SQLException {
379: throw new SQLException(
380: "This is not a Jdbc 3.0 Compliant Connection");
381: }
382:
383: public final PreparedStatement prepareStatement(String sql,
384: int resulSetType, int resultSetConcurrency,
385: int resultSetHoldability) throws SQLException {
386: throw new SQLException(
387: "This is not a Jdbc 3.0 Compliant Connection");
388: }
389:
390: public final CallableStatement prepareCall(String sql,
391: int resulSetType, int resultSetConcurrency,
392: int resultSetHoldability) throws SQLException {
393: throw new SQLException(
394: "This is not a Jdbc 3.0 Compliant Connection");
395: }
396:
397: public final PreparedStatement prepareStatement(String sql,
398: int autoGeneratedKeys) throws SQLException {
399: throw new SQLException(
400: "This is not a Jdbc 3.0 Compliant Connection");
401: }
402:
403: public final PreparedStatement prepareStatement(String sql,
404: int[] columnIndexes) throws SQLException {
405: throw new SQLException(
406: "This is not a Jdbc 3.0 Compliant Connection");
407: }
408:
409: public final PreparedStatement prepareStatement(String sql,
410: String[] columnNames) throws SQLException {
411: throw new SQLException(
412: "This is not a Jdbc 3.0 Compliant Connection");
413: }
414: /* JDBC_3_ANT_KEY --*/
415:
416: }
|