View Javadoc

1   /************************************************************************
2    * Copyright (c) 2000-2006 The Apache Software Foundation.             *
3    * All rights reserved.                                                *
4    * ------------------------------------------------------------------- *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you *
6    * may not use this file except in compliance with the License. You    *
7    * may obtain a copy of the License at:                                *
8    *                                                                     *
9    *     http://www.apache.org/licenses/LICENSE-2.0                      *
10   *                                                                     *
11   * Unless required by applicable law or agreed to in writing, software *
12   * distributed under the License is distributed on an "AS IS" BASIS,   *
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
14   * implied.  See the License for the specific language governing       *
15   * permissions and limitations under the License.                      *
16   ***********************************************************************/
17  
18  package org.apache.james.util.mordred;
19  
20  import java.io.PrintWriter;
21  import java.io.StringWriter;
22  import java.sql.CallableStatement;
23  import java.sql.Connection;
24  import java.sql.DatabaseMetaData;
25  import java.sql.PreparedStatement;
26  import java.sql.SQLException;
27  import java.sql.SQLWarning;
28  import java.sql.Statement;
29  import java.util.Map;
30  
31  /***
32   * An entry in a connection pool.
33   *
34   */
35  public class PoolConnEntry implements java.sql.Connection{
36      private static final boolean DEEP_DEBUG = false;
37  
38      // States for connections (in use, being tested, or active)
39      public final static int     AVAILABLE = 0;
40      public final static int     ACTIVE = 1;
41  
42      private JdbcDataSource      container;
43  
44      private Connection          connection;
45      private int                 status;
46      private long                lockTime;
47      private long                createDate;
48      private long                lastActivity;
49      private int                 id;
50      private java.lang.Throwable trace;
51  
52      /***
53       * Insert the method's description here.
54       * Creation date: (8/24/99 11:43:45 AM)
55       * @param conn java.sql.Connection
56       */
57      public PoolConnEntry(JdbcDataSource container, Connection conn, int id) {
58          this.container = container;
59          this.connection = conn;
60          status = AVAILABLE;
61          createDate = System.currentTimeMillis();
62          lastActivity = System.currentTimeMillis();
63          this.id = id;
64      }
65  
66      /***
67       * Locks an entry for anybody else using it
68       */
69      public synchronized boolean lock() throws SQLException {
70          if (DEEP_DEBUG) {
71              System.out.println("Trying to lock");
72          }
73  
74          if (status != PoolConnEntry.AVAILABLE) {
75              return false;
76          }
77  
78          if (DEEP_DEBUG) {
79              System.out.println("Available");
80          }
81  
82          if (false) {
83              //There really is no sense in doing this...
84              //  maybe make it a conf option at some point, but really slows
85              //  down the pooling.
86              if (connection.isClosed()) {
87                  throw new SQLException("Connection has been closed.");
88              }
89  
90              if (DEEP_DEBUG) {
91                  System.out.println("not closed");
92              }
93          }
94  
95  
96          status = PoolConnEntry.ACTIVE;
97          lockTime = System.currentTimeMillis();
98          lastActivity = lockTime;
99          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 =
126                     new StringBuffer(256)
127                             .append("Warnings on connection ")
128                             .append(id)
129                             .append(currSQLWarning);
130                 container.debug(logBuffer.toString());
131                 currSQLWarning = currSQLWarning.getNextWarning();
132             }
133             connection.clearWarnings();
134         } catch (SQLException sqle) {
135             container.debug("Error while clearing exceptions on " + id);
136             // It will probably get killed by itself before too long if this failed
137         }
138     }
139 
140 
141     /***
142      * Insert the method's description here.
143      * Creation date: (8/24/99 11:43:19 AM)
144      * @return a long representing the time this entry was created
145      */
146     public long getCreateDate() {
147         return createDate;
148     }
149 
150     /***
151      * Insert the method's description here.
152      * Creation date: (8/24/99 12:09:01 PM)
153      * @return int
154      */
155     public int getId() {
156         return id;
157     }
158 
159     /***
160      * Insert the method's description here.
161      * Creation date: (8/24/99 11:43:19 AM)
162      * @return long
163      */
164     public long getLastActivity() {
165         return lastActivity;
166     }
167 
168     /***
169      * Insert the method's description here.
170      * Creation date: (8/24/99 11:43:19 AM)
171      * @return long
172      */
173     public long getLockTime() {
174         return lockTime;
175     }
176 
177     /***
178      * Insert the method's description here.
179      * Creation date: (8/24/99 11:43:19 AM)
180      * @return int
181      */
182     public int getStatus() {
183         return status;
184     }
185 
186     /***
187      * Insert the method's description here.
188      * Creation date: (8/24/99 2:33:38 PM)
189      * @return java.lang.Throwable
190      */
191     public java.lang.Throwable getTrace() {
192         return trace;
193     }
194 
195     /***
196      * Need to clean up the connection
197      */
198     protected void finalize() {
199         container.debug("Closing connection " + id);
200         try {
201             connection.close();
202         } catch (SQLException ex) {
203             StringBuffer warnBuffer =
204                 new StringBuffer(64)
205                     .append("Cannot close connection ")
206                     .append(id)
207                     .append(" on finalize");
208             container.warn(warnBuffer.toString());
209         }
210         // Dump the stack trace of whoever created this connection
211         if (getTrace() != null) {
212             StringWriter sout = new StringWriter();
213             trace.printStackTrace(new PrintWriter(sout, true));
214             container.info(sout.toString());
215         }
216     }
217 
218     public String getString() {
219         StringBuffer poolConnStringBuffer =
220             new StringBuffer(64)
221                     .append(getId())
222                     .append(": ")
223                     .append(connection.toString());
224         return poolConnStringBuffer.toString();
225     }
226 
227 
228     /*
229      * New approach now actually has this implement a connection, as a wrapper.
230      * All calls will be passed to underlying connection.
231      * Except when closed is called, which will instead cause the releaseConnection on
232      * the parent to be executed.
233      *
234      * These are the methods from java.sql.Connection
235      */
236 
237     public void close() throws SQLException {
238         clearWarnings();
239         container.releaseConnection(this);
240     }
241 
242     /***
243      * Returns whether this entry is closed.
244      *
245      * @return whether the underlying conntection is closed
246      */
247     public boolean isClosed() throws SQLException {
248         return connection.isClosed();
249     }
250 
251 
252     public final Statement createStatement() throws SQLException {
253         return connection.createStatement();
254     }
255 
256     public final PreparedStatement prepareStatement(final String sql) throws SQLException {
257         return connection.prepareStatement(sql);
258     }
259 
260     public final CallableStatement prepareCall(final String sql) throws SQLException {
261         return connection.prepareCall(sql);
262     }
263 
264     public final String nativeSQL(final String sql) throws SQLException {
265         return connection.nativeSQL( sql );
266     }
267 
268     public final void setAutoCommit(final boolean autoCommit) throws SQLException {
269         connection.setAutoCommit( autoCommit );
270     }
271 
272     public final boolean getAutoCommit() throws SQLException {
273         return connection.getAutoCommit();
274     }
275 
276     public final void commit() throws SQLException {
277         connection.commit();
278     }
279 
280     public final void rollback() throws SQLException {
281         connection.rollback();
282     }
283 
284     public final DatabaseMetaData getMetaData() throws SQLException {
285         return connection.getMetaData();
286     }
287 
288     public final void setReadOnly( final boolean readOnly ) throws SQLException {
289         connection.setReadOnly( readOnly );
290     }
291 
292     public final boolean isReadOnly() throws SQLException {
293         return connection.isReadOnly();
294     }
295 
296     public final void setCatalog( final String catalog ) throws SQLException {
297         connection.setCatalog( catalog );
298     }
299 
300     public final String getCatalog() throws SQLException {
301         return connection.getCatalog();
302     }
303 
304     public final void setTransactionIsolation( final int level ) throws SQLException {
305         connection.setTransactionIsolation(level);
306     }
307 
308     public final int getTransactionIsolation() throws SQLException {
309         return connection.getTransactionIsolation();
310     }
311 
312     public final SQLWarning getWarnings() throws SQLException {
313         return connection.getWarnings();
314     }
315 
316     public final Statement createStatement( final int resultSetType,
317                                             final int resultSetConcurrency )
318             throws SQLException {
319         return connection.createStatement(resultSetType, resultSetConcurrency);
320     }
321 
322     public final PreparedStatement prepareStatement( final String sql,
323                                                final int resultSetType,
324                                                final int resultSetConcurrency )
325             throws SQLException {
326         return connection.prepareStatement( sql, resultSetType, resultSetConcurrency);
327     }
328 
329     public final CallableStatement prepareCall( final String sql,
330                                           final int resultSetType,
331                                           final int resultSetConcurrency )
332             throws SQLException {
333         return connection.prepareCall( sql, resultSetType, resultSetConcurrency );
334     }
335 
336     public final Map getTypeMap() throws SQLException {
337         return connection.getTypeMap();
338     }
339 
340     public final void setTypeMap( final Map map ) throws SQLException {
341         connection.setTypeMap( map );
342     }
343 
344     /*-- JDBC_3_ANT_KEY */
345     public final void setHoldability(int holdability)
346         throws SQLException
347     {
348         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
349     }
350 
351     public final int getHoldability()
352         throws SQLException
353     {
354         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
355     }
356 
357     public final java.sql.Savepoint setSavepoint()
358         throws SQLException
359     {
360         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
361     }
362 
363     public final java.sql.Savepoint setSavepoint(String savepoint)
364         throws SQLException
365     {
366         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
367     }
368 
369     public final void rollback(java.sql.Savepoint savepoint)
370         throws SQLException
371     {
372         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
373     }
374 
375     public final void releaseSavepoint(java.sql.Savepoint savepoint)
376         throws SQLException
377     {
378         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
379     }
380 
381     public final Statement createStatement(int resulSetType,
382                                            int resultSetConcurrency,
383                                            int resultSetHoldability)
384         throws SQLException
385     {
386         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
387     }
388 
389     public final PreparedStatement prepareStatement(String sql,
390                                         int resulSetType,
391                                         int resultSetConcurrency,
392                                         int resultSetHoldability)
393         throws SQLException
394     {
395         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
396     }
397 
398     public final CallableStatement prepareCall(String sql,
399                                         int resulSetType,
400                                         int resultSetConcurrency,
401                                         int resultSetHoldability)
402         throws SQLException
403     {
404         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
405     }
406 
407     public final PreparedStatement prepareStatement(String sql,
408                                         int autoGeneratedKeys)
409         throws SQLException
410     {
411         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
412     }
413 
414     public final PreparedStatement prepareStatement(String sql,
415                                         int[] columnIndexes)
416         throws SQLException
417     {
418         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
419     }
420 
421     public final PreparedStatement prepareStatement(String sql,
422                                         String[] columnNames)
423         throws SQLException
424     {
425         throw new SQLException("This is not a Jdbc 3.0 Compliant Connection");
426     }
427     /* JDBC_3_ANT_KEY --*/
428 
429 }