View Javadoc

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