KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mchange > v2 > c3p0 > impl > C3P0PooledConnectionPool


1 /*
2  * Distributed as part of c3p0 v.0.9.1
3  *
4  * Copyright (C) 2005 Machinery For Change, Inc.
5  *
6  * Author: Steve Waldman <swaldman@mchange.com>
7  *
8  * This library is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License version 2.1, as
10  * published by the Free Software Foundation.
11  *
12  * This software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this software; see the file LICENSE. If not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */

22
23
24 package com.mchange.v2.c3p0.impl;
25
26 import com.mchange.v2.c3p0.stmt.*;
27 import com.mchange.v2.c3p0.ConnectionCustomizer;
28 import com.mchange.v2.c3p0.SQLWarnings;
29 import com.mchange.v2.c3p0.UnifiedConnectionTester;
30 import com.mchange.v2.c3p0.WrapperConnectionPoolDataSource;
31
32 import java.sql.Connection JavaDoc;
33 import java.sql.SQLException JavaDoc;
34 import java.sql.SQLWarning JavaDoc;
35 import java.util.LinkedList JavaDoc;
36
37 import javax.sql.ConnectionEvent JavaDoc;
38 import javax.sql.ConnectionEventListener JavaDoc;
39 import javax.sql.ConnectionPoolDataSource JavaDoc;
40 import javax.sql.PooledConnection JavaDoc;
41
42 import com.mchange.v1.db.sql.ConnectionUtils;
43 import com.mchange.v2.async.AsynchronousRunner;
44 import com.mchange.v2.async.ThreadPoolAsynchronousRunner;
45 import com.mchange.v2.log.MLevel;
46 import com.mchange.v2.log.MLog;
47 import com.mchange.v2.log.MLogger;
48 import com.mchange.v2.c3p0.ConnectionTester;
49 import com.mchange.v2.c3p0.QueryConnectionTester;
50 import com.mchange.v2.resourcepool.CannotAcquireResourceException;
51 import com.mchange.v2.resourcepool.ResourcePool;
52 import com.mchange.v2.resourcepool.ResourcePoolException;
53 import com.mchange.v2.resourcepool.ResourcePoolFactory;
54 import com.mchange.v2.resourcepool.TimeoutException;
55 import com.mchange.v2.sql.SqlUtils;
56
57 public final class C3P0PooledConnectionPool
58 {
59     private final static boolean ASYNCHRONOUS_CONNECTION_EVENT_LISTENER = false;
60
61     private final static Throwable JavaDoc[] EMPTY_THROWABLE_HOLDER = new Throwable JavaDoc[1];
62
63     final static MLogger logger = MLog.getLogger( C3P0PooledConnectionPool.class );
64
65     final ResourcePool rp;
66     final ConnectionEventListener JavaDoc cl = new ConnectionEventListenerImpl();
67
68     final ConnectionTester connectionTester;
69     final GooGooStatementCache scache;
70
71     final int checkoutTimeout;
72
73     final AsynchronousRunner sharedTaskRunner;
74
75     final ThrowableHolderPool thp = new ThrowableHolderPool();
76
77     C3P0PooledConnectionPool( final ConnectionPoolDataSource cpds,
78                     final DbAuth auth,
79                     int min,
80                     int max,
81                     int start,
82                     int inc,
83                     int acq_retry_attempts,
84                     int acq_retry_delay,
85                     boolean break_after_acq_failure,
86                     int checkoutTimeout, //milliseconds
87
int idleConnectionTestPeriod, //seconds
88
int maxIdleTime, //seconds
89
int maxIdleTimeExcessConnections, //seconds
90
int maxConnectionAge, //seconds
91
int propertyCycle, //seconds
92
int unreturnedConnectionTimeout, //seconds
93
boolean debugUnreturnedConnectionStackTraces,
94                     final boolean testConnectionOnCheckout,
95                     final boolean testConnectionOnCheckin,
96                     int maxStatements,
97                     int maxStatementsPerConnection,
98                     final ConnectionTester connectionTester,
99                     final ConnectionCustomizer connectionCustomizer,
100                     final String JavaDoc testQuery,
101                     final ResourcePoolFactory fact,
102                     ThreadPoolAsynchronousRunner taskRunner,
103                     final String JavaDoc parentDataSourceIdentityToken) throws SQLException JavaDoc
104                     {
105         try
106         {
107             if (maxStatements > 0 && maxStatementsPerConnection > 0)
108                 this.scache = new DoubleMaxStatementCache( taskRunner, maxStatements, maxStatementsPerConnection );
109             else if (maxStatementsPerConnection > 0)
110                 this.scache = new PerConnectionMaxOnlyStatementCache( taskRunner, maxStatementsPerConnection );
111             else if (maxStatements > 0)
112                 this.scache = new GlobalMaxOnlyStatementCache( taskRunner, maxStatements );
113             else
114                 this.scache = null;
115
116             this.connectionTester = connectionTester;
117
118             this.checkoutTimeout = checkoutTimeout;
119
120             this.sharedTaskRunner = taskRunner;
121
122             class PooledConnectionResourcePoolManager implements ResourcePool.Manager
123             {
124                 //SynchronizedIntHolder totalOpenedCounter = new SynchronizedIntHolder();
125
//SynchronizedIntHolder connectionCounter = new SynchronizedIntHolder();
126
//SynchronizedIntHolder failedCloseCounter = new SynchronizedIntHolder();
127

128                 final boolean connectionTesterIsDefault = (connectionTester instanceof DefaultConnectionTester);
129                 final boolean c3p0PooledConnections = (cpds instanceof WrapperConnectionPoolDataSource);
130
131                 public Object JavaDoc acquireResource() throws Exception JavaDoc
132                 {
133                     PooledConnection JavaDoc out;
134
135                     if ( connectionCustomizer == null)
136                     {
137                         out = (auth.equals( C3P0ImplUtils.NULL_AUTH ) ?
138                                cpds.getPooledConnection() :
139                                cpds.getPooledConnection( auth.getUser(),
140                                                          auth.getPassword() ) );
141                     }
142                     else
143                     {
144                         try
145                         {
146                             WrapperConnectionPoolDataSourceBase wcpds = (WrapperConnectionPoolDataSourceBase) cpds;
147
148                             out = (auth.equals( C3P0ImplUtils.NULL_AUTH ) ?
149                                    wcpds.getPooledConnection( connectionCustomizer, parentDataSourceIdentityToken ) :
150                                    wcpds.getPooledConnection( auth.getUser(),
151                                                               auth.getPassword(),
152                                                               connectionCustomizer, parentDataSourceIdentityToken ) );
153                         }
154                         catch (ClassCastException JavaDoc e)
155                         {
156                             throw SqlUtils.toSQLException("Cannot use a ConnectionCustomizer with a non-c3p0 ConnectionPoolDataSource." +
157                                             " ConnectionPoolDataSource: " + cpds.getClass().getName(), e);
158                         }
159                     }
160
161                     //connectionCounter.increment();
162
//totalOpenedCounter.increment();
163

164                     try
165                     {
166                         if (scache != null)
167                         {
168                             if (c3p0PooledConnections)
169                                 ((AbstractC3P0PooledConnection) out).initStatementCache(scache);
170                             else
171                             {
172                                 // System.err.print("Warning! StatementPooling not ");
173
// System.err.print("implemented for external (non-c3p0) ");
174
// System.err.println("ConnectionPoolDataSources.");
175

176                                 logger.warning("StatementPooling not " +
177                                                 "implemented for external (non-c3p0) " +
178                                 "ConnectionPoolDataSources.");
179                             }
180                         }
181                         
182                         // log and clear any SQLWarnings present upon acquisition
183
Connection JavaDoc con = null;
184                         try
185                         {
186                             con = out.getConnection();
187                             SQLWarnings.logAndClearWarnings( con );
188                         }
189                         finally
190                         {
191                             //invalidate the proxy Connection
192
ConnectionUtils.attemptClose( con );
193                         }
194                         
195                         out.addConnectionEventListener( cl );
196                         return out;
197                     }
198                     catch (Exception JavaDoc e)
199                     {
200                         if (logger.isLoggable( MLevel.WARNING ))
201                             logger.warning("A PooledConnection was acquired, but an Exception occurred while preparing it for use. " +
202                             "Attempting to destroy.");
203                         try { destroyResource( out ); }
204                         catch (Exception JavaDoc e2)
205                         {
206                             if (logger.isLoggable( MLevel.WARNING ))
207                                 logger.log( MLevel.WARNING,
208                                                 "An Exception occurred while trying to close partially acquired PooledConnection.",
209                                                 e2 );
210                         }
211
212                         throw e;
213                     }
214                     finally
215                     {
216                         if (logger.isLoggable( MLevel.FINEST ))
217                             logger.finest(this + ".acquireResource() returning. " );
218                         //"Currently open Connections: " + connectionCounter.getValue() +
219
//"; Failed close count: " + failedCloseCounter.getValue() +
220
//"; Total processed by this pool: " + totalOpenedCounter.getValue());
221
}
222                 }
223
224                 // REFURBISHMENT:
225
// the PooledConnection refurbishes itself when
226
// its Connection view is closed, prior to being
227
// checked back in to the pool. But we still may want to
228
// test to make sure it is still good.
229

230                 public void refurbishResourceOnCheckout( Object JavaDoc resc ) throws Exception JavaDoc
231                 {
232                     if ( testConnectionOnCheckout )
233                     {
234                         if ( logger.isLoggable( MLevel.FINER ) )
235                             finerLoggingTestPooledConnection( resc, "CHECKOUT" );
236                         else
237                             testPooledConnection( resc );
238                     }
239                     if ( connectionCustomizer != null )
240                     {
241                         Connection JavaDoc physicalConnection = null;
242                         try
243                         {
244                             physicalConnection = ((AbstractC3P0PooledConnection) resc).getPhysicalConnection();
245                             connectionCustomizer.onCheckOut( physicalConnection, parentDataSourceIdentityToken );
246                         }
247                         catch (ClassCastException JavaDoc e)
248                         {
249                             throw SqlUtils.toSQLException("Cannot use a ConnectionCustomizer with a non-c3p0 PooledConnection." +
250                                             " PooledConnection: " + resc +
251                                             "; ConnectionPoolDataSource: " + cpds.getClass().getName(), e);
252                         }
253                     }
254                 }
255
256                 public void refurbishResourceOnCheckin( Object JavaDoc resc ) throws Exception JavaDoc
257                 {
258                     if ( connectionCustomizer != null )
259                     {
260                         Connection JavaDoc physicalConnection = null;
261                         try
262                         {
263                             physicalConnection = ((AbstractC3P0PooledConnection) resc).getPhysicalConnection();
264                             connectionCustomizer.onCheckIn( physicalConnection, parentDataSourceIdentityToken );
265                             SQLWarnings.logAndClearWarnings( physicalConnection );
266                         }
267                         catch (ClassCastException JavaDoc e)
268                         {
269                             throw SqlUtils.toSQLException("Cannot use a ConnectionCustomizer with a non-c3p0 PooledConnection." +
270                                             " PooledConnection: " + resc +
271                                             "; ConnectionPoolDataSource: " + cpds.getClass().getName(), e);
272                         }
273                     }
274                     else
275                     {
276                         PooledConnection JavaDoc pc = (PooledConnection JavaDoc) resc;
277                         Connection JavaDoc con = null;
278
279                         try
280                         {
281                             //we don't want any callbacks while we're clearing warnings
282
pc.removeConnectionEventListener( cl );
283
284                             con = pc.getConnection();
285                             SQLWarnings.logAndClearWarnings(con);
286                         }
287                         finally
288                         {
289                             // close the proxy Connection
290
ConnectionUtils.attemptClose(con);
291                             
292                             pc.addConnectionEventListener( cl );
293                         }
294                     }
295                     
296                     if ( testConnectionOnCheckin )
297                     {
298                         if ( logger.isLoggable( MLevel.FINER ) )
299                             finerLoggingTestPooledConnection( resc, "CHECKIN" );
300                         else
301                             testPooledConnection( resc );
302                     }
303                 }
304
305                 public void refurbishIdleResource( Object JavaDoc resc ) throws Exception JavaDoc
306                 {
307                     if ( logger.isLoggable( MLevel.FINER ) )
308                         finerLoggingTestPooledConnection( resc, "IDLE CHECK" );
309                     else
310                         testPooledConnection( resc );
311                 }
312
313                 private void finerLoggingTestPooledConnection(Object JavaDoc resc, String JavaDoc testImpetus) throws Exception JavaDoc
314                 {
315                     logger.finer("Testing PooledConnection [" + resc + "] on " + testImpetus + ".");
316                     try
317                     {
318                         testPooledConnection( resc );
319                         logger.finer("Test of PooledConnection [" + resc + "] on "+testImpetus+" has SUCCEEDED.");
320                     }
321                     catch (Exception JavaDoc e)
322                     {
323                         logger.log(MLevel.FINER, "Test of PooledConnection [" + resc + "] on "+testImpetus+" has FAILED.", e);
324                         e.fillInStackTrace();
325                         throw e;
326                     }
327                 }
328
329                 private void testPooledConnection(Object JavaDoc resc) throws Exception JavaDoc
330                 {
331                     PooledConnection JavaDoc pc = (PooledConnection JavaDoc) resc;
332
333                     Throwable JavaDoc[] throwableHolder = EMPTY_THROWABLE_HOLDER;
334                     int status;
335                     Connection JavaDoc conn = null;
336                     Throwable JavaDoc rootCause = null;
337                     try
338                     {
339                         //we don't want any callbacks while we're testing the resource
340
pc.removeConnectionEventListener( cl );
341
342                         conn = pc.getConnection(); //checkout proxy connection
343

344                         // if this is a c3p0 pooled-connection, let's get underneath the
345
// proxy wrapper, and test the physical connection sometimes.
346
// this is faster, when the testQuery would not otherwise be cached,
347
// and it avoids a potential statusOnException() double-check by the
348
// PooledConnection implementation should the test query provoke an
349
// Exception
350
Connection JavaDoc testConn;
351                         if (scache != null) //when there is a statement cache...
352
{
353                             // if it's the slow, default query, faster to test the raw Connection
354
if (testQuery == null && connectionTesterIsDefault && c3p0PooledConnections)
355                                 testConn = ((AbstractC3P0PooledConnection) pc).getPhysicalConnection();
356                             else //test will likely be faster on the proxied Connection, because the test query is probably cached
357
testConn = conn;
358                         }
359                         else //where there's no statement cache, better to use the physical connection, if we can get it
360
{
361                             if (c3p0PooledConnections)
362                                 testConn = ((AbstractC3P0PooledConnection) pc).getPhysicalConnection();
363                             else
364                                 testConn = conn;
365                         }
366
367                         if ( testQuery == null )
368                             status = connectionTester.activeCheckConnection( testConn );
369                         else
370                         {
371                             if (connectionTester instanceof UnifiedConnectionTester)
372                             {
373                                 throwableHolder = thp.getThrowableHolder();
374                                 status = ((UnifiedConnectionTester) connectionTester).activeCheckConnection( testConn, testQuery, throwableHolder );
375                             }
376                             else if (connectionTester instanceof QueryConnectionTester)
377                                 status = ((QueryConnectionTester) connectionTester).activeCheckConnection( testConn, testQuery );
378                             else
379                             {
380                                 // System.err.println("[c3p0] WARNING: testQuery '" + testQuery +
381
// "' ignored. Please set a ConnectionTester that implements " +
382
// "com.mchange.v2.c3p0.advanced.QueryConnectionTester, or use the " +
383
// "DefaultConnectionTester, to test with the testQuery.");
384

385                                 logger.warning("[c3p0] testQuery '" + testQuery +
386                                                 "' ignored. Please set a ConnectionTester that implements " +
387                                                 "com.mchange.v2.c3p0.QueryConnectionTester, or use the " +
388                                 "DefaultConnectionTester, to test with the testQuery.");
389                                 status = connectionTester.activeCheckConnection( testConn );
390                             }
391                         }
392                     }
393                     catch (Exception JavaDoc e)
394                     {
395                         if (Debug.DEBUG)
396                             logger.log(MLevel.FINE, "A Connection test failed with an Exception.", e);
397                         //e.printStackTrace();
398
status = ConnectionTester.CONNECTION_IS_INVALID;
399 // System.err.println("rootCause ------>");
400
// e.printStackTrace();
401
rootCause = e;
402                     }
403                     finally
404                     {
405                         if (rootCause == null)
406                             rootCause = throwableHolder[0];
407                         else if (throwableHolder[0] != null && logger.isLoggable(MLevel.FINE))
408                             logger.log(MLevel.FINE, "Internal Connection Test Exception", throwableHolder[0]);
409                         
410                         if (throwableHolder != EMPTY_THROWABLE_HOLDER)
411                             thp.returnThrowableHolder( throwableHolder );
412                         
413                         ConnectionUtils.attemptClose( conn ); //invalidate proxy connection
414
pc.addConnectionEventListener( cl ); //should we move this to CONNECTION_IS_OKAY case? (it should work either way)
415
}
416
417                     switch (status)
418                     {
419                     case ConnectionTester.CONNECTION_IS_OKAY:
420                         break; //no problem, babe
421
case ConnectionTester.DATABASE_IS_INVALID:
422                         rp.resetPool();
423                         //intentional cascade...
424
case ConnectionTester.CONNECTION_IS_INVALID:
425                         Exception JavaDoc throwMe;
426                         if (rootCause == null)
427                             throwMe = new SQLException JavaDoc("Connection is invalid");
428                         else
429                             throwMe = SqlUtils.toSQLException("Connection is invalid", rootCause);
430                         throw throwMe;
431                     default:
432                         throw new Error JavaDoc("Bad Connection Tester (" +
433                                         connectionTester + ") " +
434                                         "returned invalid status (" + status + ").");
435                     }
436                 }
437
438                 public void destroyResource(Object JavaDoc resc) throws Exception JavaDoc
439                 {
440                     try
441                     {
442                         if ( connectionCustomizer != null )
443                         {
444                             Connection JavaDoc physicalConnection = null;
445                             try
446                             {
447                                 physicalConnection = ((AbstractC3P0PooledConnection) resc).getPhysicalConnection();
448                                 connectionCustomizer.onDestroy( physicalConnection, parentDataSourceIdentityToken );
449                             }
450                             catch (ClassCastException JavaDoc e)
451                             {
452                                 throw SqlUtils.toSQLException("Cannot use a ConnectionCustomizer with a non-c3p0 PooledConnection." +
453                                                 " PooledConnection: " + resc +
454                                                 "; ConnectionPoolDataSource: " + cpds.getClass().getName(), e);
455                             }
456                             catch (Exception JavaDoc e)
457                             {
458                                 if (logger.isLoggable( MLevel.WARNING ))
459                                     logger.log( MLevel.WARNING,
460                                                     "An exception occurred while executing the onDestroy() method of " + connectionCustomizer +
461                                                     ". c3p0 will attempt to destroy the target Connection regardless, but this issue " +
462                                                     " should be investigated and fixed.",
463                                                     e );
464                             }
465                         }
466
467                         if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX && logger.isLoggable( MLevel.FINER ))
468                             logger.log( MLevel.FINER, "Preparing to destroy PooledConnection: " + resc);
469
470                         ((PooledConnection JavaDoc) resc).close();
471
472                         // inaccurate, as Connections can be removed more than once
473
//connectionCounter.decrement();
474

475                         if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX && logger.isLoggable( MLevel.FINER ))
476                             logger.log( MLevel.FINER,
477                                             "Successfully destroyed PooledConnection: " + resc );
478                         //". Currently open Connections: " + connectionCounter.getValue() +
479
//"; Failed close count: " + failedCloseCounter.getValue() +
480
//"; Total processed by this pool: " + totalOpenedCounter.getValue());
481
}
482                     catch (Exception JavaDoc e)
483                     {
484                         //failedCloseCounter.increment();
485

486                         if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX && logger.isLoggable( MLevel.FINER ))
487                             logger.log( MLevel.FINER, "Failed to destroy PooledConnection: " + resc );
488                         //". Currently open Connections: " + connectionCounter.getValue() +
489
//"; Failed close count: " + failedCloseCounter.getValue() +
490
//"; Total processed by this pool: " + totalOpenedCounter.getValue());
491

492                         throw e;
493                     }
494                 }
495             }
496
497             ResourcePool.Manager manager = new PooledConnectionResourcePoolManager();
498
499             synchronized (fact)
500             {
501                 fact.setMin( min );
502                 fact.setMax( max );
503                 fact.setStart( start );
504                 fact.setIncrement( inc );
505                 fact.setIdleResourceTestPeriod( idleConnectionTestPeriod * 1000);
506                 fact.setResourceMaxIdleTime( maxIdleTime * 1000 );
507                 fact.setExcessResourceMaxIdleTime( maxIdleTimeExcessConnections * 1000 );
508                 fact.setResourceMaxAge( maxConnectionAge * 1000 );
509                 fact.setExpirationEnforcementDelay( propertyCycle * 1000 );
510                 fact.setDestroyOverdueResourceTime( unreturnedConnectionTimeout * 1000 );
511                 fact.setDebugStoreCheckoutStackTrace( debugUnreturnedConnectionStackTraces );
512                 fact.setAcquisitionRetryAttempts( acq_retry_attempts );
513                 fact.setAcquisitionRetryDelay( acq_retry_delay );
514                 fact.setBreakOnAcquisitionFailure( break_after_acq_failure );
515                 rp = fact.createPool( manager );
516             }
517         }
518         catch (ResourcePoolException e)
519         { throw SqlUtils.toSQLException(e); }
520                     }
521
522     public PooledConnection JavaDoc checkoutPooledConnection() throws SQLException JavaDoc
523     {
524         //System.err.println(this + " -- CHECKOUT");
525
try { return (PooledConnection JavaDoc) rp.checkoutResource( checkoutTimeout ); }
526         catch (TimeoutException e)
527         { throw SqlUtils.toSQLException("An attempt by a client to checkout a Connection has timed out.", e); }
528         catch (CannotAcquireResourceException e)
529         { throw SqlUtils.toSQLException("Connections could not be acquired from the underlying database!", "08001", e); }
530         catch (Exception JavaDoc e)
531         { throw SqlUtils.toSQLException(e); }
532     }
533
534     public void checkinPooledConnection(PooledConnection JavaDoc pcon) throws SQLException JavaDoc
535     {
536         //System.err.println(this + " -- CHECKIN");
537
try { rp.checkinResource( pcon ); }
538         catch (ResourcePoolException e)
539         { throw SqlUtils.toSQLException(e); }
540     }
541
542     public float getEffectivePropertyCycle() throws SQLException JavaDoc
543     {
544         try
545         { return rp.getEffectiveExpirationEnforcementDelay() / 1000f; }
546         catch (ResourcePoolException e)
547         { throw SqlUtils.toSQLException(e); }
548     }
549
550     public int getNumThreadsAwaitingCheckout() throws SQLException JavaDoc
551     {
552         try
553         { return rp.getNumCheckoutWaiters(); }
554         catch (ResourcePoolException e)
555         { throw SqlUtils.toSQLException(e); }
556     }
557
558     public int getStatementCacheNumStatements()
559     { return scache == null ? 0 : scache.getNumStatements(); }
560
561     public int getStatementCacheNumCheckedOut()
562     { return scache == null ? 0 : scache.getNumStatementsCheckedOut(); }
563
564     public int getStatementCacheNumConnectionsWithCachedStatements()
565     { return scache == null ? 0 : scache.getNumConnectionsWithCachedStatements(); }
566
567     public String JavaDoc dumpStatementCacheStatus()
568     { return scache == null ? "Statement caching disabled." : scache.dumpStatementCacheStatus(); }
569
570     public void close() throws SQLException JavaDoc
571     { close( true ); }
572
573     public void close( boolean close_outstanding_connections ) throws SQLException JavaDoc
574     {
575         // System.err.println(this + " closing.");
576
Exception JavaDoc throwMe = null;
577
578         try { if (scache != null) scache.close(); }
579         catch (SQLException JavaDoc e)
580         { throwMe = e; }
581
582         try
583         { rp.close( close_outstanding_connections ); }
584         catch (ResourcePoolException e)
585         {
586             if ( throwMe != null && logger.isLoggable( MLevel.WARNING ) )
587                 logger.log( MLevel.WARNING, "An Exception occurred while closing the StatementCache.", throwMe);
588             throwMe = e;
589         }
590
591         if (throwMe != null)
592             throw SqlUtils.toSQLException( throwMe );
593     }
594
595     class ConnectionEventListenerImpl implements ConnectionEventListener JavaDoc
596     {
597
598         //
599
// We might want to check Connections in asynchronously,
600
// because this is called
601
// (indirectly) from a sync'ed method of NewPooledConnection, but
602
// NewPooledConnection may be closed synchronously from a sync'ed
603
// method of the resource pool, leading to a deadlock. Checking
604
// Connections in asynchronously breaks the cycle.
605
//
606
// But then we want checkins to happen quickly and reliably,
607
// whereas pool shutdowns are rare, so perhaps it's best to
608
// leave this synchronous, and let the closing of pooled
609
// resources on pool closes happen asynchronously to break
610
// the deadlock.
611
//
612
// For now we're leaving both versions around, but with faster
613
// and more reliable synchronous checkin enabled, and async closing
614
// of resources in BasicResourcePool.close().
615
//
616
public void connectionClosed(final ConnectionEvent JavaDoc evt)
617         {
618             //System.err.println("Checking in: " + evt.getSource());
619

620             if (ASYNCHRONOUS_CONNECTION_EVENT_LISTENER)
621             {
622                 Runnable JavaDoc r = new Runnable JavaDoc()
623                 {
624                     public void run()
625                     { doCheckinResource( evt ); }
626                 };
627                 sharedTaskRunner.postRunnable( r );
628             }
629             else
630                 doCheckinResource( evt );
631         }
632
633         private void doCheckinResource(ConnectionEvent JavaDoc evt)
634         {
635             try
636             { rp.checkinResource( evt.getSource() ); }
637             catch (Exception JavaDoc e)
638             {
639                 //e.printStackTrace();
640
logger.log( MLevel.WARNING,
641                                 "An Exception occurred while trying to check a PooledConection into a ResourcePool.",
642                                 e );
643             }
644         }
645
646         //
647
// We might want to update the pool asynchronously, because this is called
648
// (indirectly) from a sync'ed method of NewPooledConnection, but
649
// NewPooledConnection may be closed synchronously from a sync'ed
650
// method of the resource pool, leading to a deadlock. Updating
651
// pool status asynchronously breaks the cycle.
652
//
653
// But then we want checkins to happen quickly and reliably,
654
// whereas pool shutdowns are rare, so perhaps it's best to
655
// leave all ConnectionEvent handling synchronous, and let the closing of pooled
656
// resources on pool closes happen asynchronously to break
657
// the deadlock.
658
//
659
// For now we're leaving both versions around, but with faster
660
// and more reliable synchrounous ConnectionEventHandling enabled, and async closing
661
// of resources in BasicResourcePool.close().
662
//
663
public void connectionErrorOccurred(final ConnectionEvent JavaDoc evt)
664         {
665 // System.err.println("CONNECTION ERROR OCCURRED!");
666
// System.err.println();
667
if ( logger.isLoggable( MLevel.FINE ) )
668                 logger.fine("CONNECTION ERROR OCCURRED!");
669
670             final PooledConnection JavaDoc pc = (PooledConnection JavaDoc) evt.getSource();
671             int status;
672             if (pc instanceof C3P0PooledConnection)
673                 status = ((C3P0PooledConnection) pc).getConnectionStatus();
674             else if (pc instanceof NewPooledConnection)
675                 status = ((NewPooledConnection) pc).getConnectionStatus();
676             else //default to invalid connection, but not invalid database
677
status = ConnectionTester.CONNECTION_IS_INVALID;
678
679             final int final_status = status;
680
681             if (ASYNCHRONOUS_CONNECTION_EVENT_LISTENER)
682             {
683                 Runnable JavaDoc r = new Runnable JavaDoc()
684                 {
685                     public void run()
686                     { doMarkPoolStatus( pc, final_status ); }
687                 };
688                 sharedTaskRunner.postRunnable( r );
689             }
690             else
691                 doMarkPoolStatus( pc, final_status );
692         }
693
694         private void doMarkPoolStatus(PooledConnection JavaDoc pc, int status)
695         {
696             try
697             {
698                 switch (status)
699                 {
700                 case ConnectionTester.CONNECTION_IS_OKAY:
701                     throw new RuntimeException JavaDoc("connectionErrorOcccurred() should only be " +
702                     "called for errors fatal to the Connection.");
703                 case ConnectionTester.CONNECTION_IS_INVALID:
704                     rp.markBroken( pc );
705                     break;
706                 case ConnectionTester.DATABASE_IS_INVALID:
707                     if (logger.isLoggable(MLevel.WARNING))
708                         logger.warning("A ConnectionTest has failed, reporting that all previously acquired Connections are likely invalid. " +
709                         "The pool will be reset.");
710                     rp.resetPool();
711                     break;
712                 default:
713                     throw new RuntimeException JavaDoc("Bad Connection Tester (" + connectionTester + ") " +
714                                     "returned invalid status (" + status + ").");
715                 }
716             }
717             catch ( ResourcePoolException e )
718             {
719                 //System.err.println("Uh oh... our resource pool is probably broken!");
720
//e.printStackTrace();
721
logger.log(MLevel.WARNING, "Uh oh... our resource pool is probably broken!", e);
722             }
723         }
724     }
725
726     public int getNumConnections() throws SQLException JavaDoc
727     {
728         try { return rp.getPoolSize(); }
729         catch ( Exception JavaDoc e )
730         {
731             //e.printStackTrace();
732
logger.log( MLevel.WARNING, null, e );
733             throw SqlUtils.toSQLException( e );
734         }
735     }
736
737     public int getNumIdleConnections() throws SQLException JavaDoc
738     {
739         try { return rp.getAvailableCount(); }
740         catch ( Exception JavaDoc e )
741         {
742             //e.printStackTrace();
743
logger.log( MLevel.WARNING, null, e );
744             throw SqlUtils.toSQLException( e );
745         }
746     }
747
748     public int getNumBusyConnections() throws SQLException JavaDoc
749     {
750         try
751         {
752             synchronized ( rp )
753             { return (rp.getAwaitingCheckinCount() - rp.getExcludedCount()); }
754         }
755         catch ( Exception JavaDoc e )
756         {
757             //e.printStackTrace();
758
logger.log( MLevel.WARNING, null, e );
759             throw SqlUtils.toSQLException( e );
760         }
761     }
762
763     public int getNumUnclosedOrphanedConnections() throws SQLException JavaDoc
764     {
765         try { return rp.getExcludedCount(); }
766         catch ( Exception JavaDoc e )
767         {
768             //e.printStackTrace();
769
logger.log( MLevel.WARNING, null, e );
770             throw SqlUtils.toSQLException( e );
771         }
772     }
773     
774     public long getStartTime() throws SQLException JavaDoc
775     {
776         try { return rp.getStartTime(); }
777         catch ( Exception JavaDoc e )
778         {
779             //e.printStackTrace();
780
logger.log( MLevel.WARNING, null, e );
781             throw SqlUtils.toSQLException( e );
782         }
783     }
784
785     public long getUpTime() throws SQLException JavaDoc
786     {
787         try { return rp.getUpTime(); }
788         catch ( Exception JavaDoc e )
789         {
790             //e.printStackTrace();
791
logger.log( MLevel.WARNING, null, e );
792             throw SqlUtils.toSQLException( e );
793         }
794     }
795
796     public long getNumFailedCheckins() throws SQLException JavaDoc
797     {
798         try { return rp.getNumFailedCheckins(); }
799         catch ( Exception JavaDoc e )
800         {
801             //e.printStackTrace();
802
logger.log( MLevel.WARNING, null, e );
803             throw SqlUtils.toSQLException( e );
804         }
805     }
806
807     public long getNumFailedCheckouts() throws SQLException JavaDoc
808     {
809         try { return rp.getNumFailedCheckouts(); }
810         catch ( Exception JavaDoc e )
811         {
812             //e.printStackTrace();
813
logger.log( MLevel.WARNING, null, e );
814             throw SqlUtils.toSQLException( e );
815         }
816     }
817
818     public long getNumFailedIdleTests() throws SQLException JavaDoc
819     {
820         try { return rp.getNumFailedIdleTests(); }
821         catch ( Exception JavaDoc e )
822         {
823             //e.printStackTrace();
824
logger.log( MLevel.WARNING, null, e );
825             throw SqlUtils.toSQLException( e );
826         }
827     }
828
829     public Throwable JavaDoc getLastCheckinFailure() throws SQLException JavaDoc
830     {
831         try { return rp.getLastCheckinFailure(); }
832         catch ( Exception JavaDoc e )
833         {
834             //e.printStackTrace();
835
logger.log( MLevel.WARNING, null, e );
836             throw SqlUtils.toSQLException( e );
837         }
838     }
839
840     public Throwable JavaDoc getLastCheckoutFailure() throws SQLException JavaDoc
841     {
842         try { return rp.getLastCheckoutFailure(); }
843         catch ( Exception JavaDoc e )
844         {
845             //e.printStackTrace();
846
logger.log( MLevel.WARNING, null, e );
847             throw SqlUtils.toSQLException( e );
848         }
849     }
850
851     public Throwable JavaDoc getLastIdleTestFailure() throws SQLException JavaDoc
852     {
853         try { return rp.getLastIdleCheckFailure(); }
854         catch ( Exception JavaDoc e )
855         {
856             //e.printStackTrace();
857
logger.log( MLevel.WARNING, null, e );
858             throw SqlUtils.toSQLException( e );
859         }
860     }
861
862     public Throwable JavaDoc getLastConnectionTestFailure() throws SQLException JavaDoc
863     {
864         try { return rp.getLastResourceTestFailure(); }
865         catch ( Exception JavaDoc e )
866         {
867             //e.printStackTrace();
868
logger.log( MLevel.WARNING, null, e );
869             throw SqlUtils.toSQLException( e );
870         }
871     }
872     
873     public Throwable JavaDoc getLastAcquisitionFailure() throws SQLException JavaDoc
874     {
875         try { return rp.getLastAcquisitionFailure(); }
876         catch ( Exception JavaDoc e )
877         {
878             //e.printStackTrace();
879
logger.log( MLevel.WARNING, null, e );
880             throw SqlUtils.toSQLException( e );
881         }
882     }
883
884     /**
885      * Discards all Connections managed by the pool
886      * and reacquires new Connections to populate.
887      * Current checked out Connections will still
888      * be valid, and should still be checked into the
889      * pool (so the pool can destroy them).
890      */

891     public void reset() throws SQLException JavaDoc
892     {
893         try { rp.resetPool(); }
894         catch ( Exception JavaDoc e )
895         {
896             //e.printStackTrace();
897
logger.log( MLevel.WARNING, null, e );
898             throw SqlUtils.toSQLException( e );
899         }
900     }
901
902     final static class ThrowableHolderPool
903     {
904         LinkedList JavaDoc l = new LinkedList JavaDoc();
905
906         synchronized Throwable JavaDoc[] getThrowableHolder()
907         {
908             if (l.size() == 0)
909                 return new Throwable JavaDoc[1];
910             else
911                 return (Throwable JavaDoc[]) l.remove(0);
912         }
913
914         synchronized void returnThrowableHolder(Throwable JavaDoc[] th)
915         {
916             th[0] = null;
917             l.add(th);
918         }
919     }
920     
921 }
922
Popular Tags