KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > proxool > ConnectionPool


1 /*
2  * This software is released under a licence similar to the Apache Software Licence.
3  * See org.logicalcobwebs.proxool.package.html for details.
4  * The latest version is available at http://proxool.sourceforge.net
5  */

6 package org.logicalcobwebs.proxool;
7
8 import java.sql.Connection JavaDoc;
9 import java.sql.SQLException JavaDoc;
10 import java.util.Collection JavaDoc;
11 import java.util.Date JavaDoc;
12 import java.util.HashSet JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.List JavaDoc;
15 import java.util.Set JavaDoc;
16 import java.util.TreeSet JavaDoc;
17
18 import org.logicalcobwebs.concurrent.ReaderPreferenceReadWriteLock;
19 import org.logicalcobwebs.concurrent.WriterPreferenceReadWriteLock;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.logicalcobwebs.proxool.admin.Admin;
23 import org.logicalcobwebs.proxool.util.FastArrayList;
24
25 /**
26  * This is where most things happen. (In fact, probably too many things happen in this one
27  * class).
28  * @version $Revision: 1.84 $, $Date: 2006/03/23 11:44:57 $
29  * @author billhorsman
30  * @author $Author: billhorsman $ (current maintainer)
31  */

32 class ConnectionPool implements ConnectionPoolStatisticsIF {
33
34     /**
35      * Use this for messages that aren't useful for the pool specific log
36      */

37     private static final Log LOG = LogFactory.getLog(ConnectionPool.class);
38
39     /**
40      * Here we deviate from the standard of using the classname for the log
41      * name. Here we want to use the alias for the pool so that we can log
42      * each pool to different places. So we have to instantiate the log later.
43      */

44     private Log log;
45
46     private ReaderPreferenceReadWriteLock connectionStatusReadWriteLock = new ReaderPreferenceReadWriteLock();
47
48     /**
49      * If you want to shutdown the pool you should get a write lock on this. And if you use the pool then
50      * get a read lock. This stops us trying to shutdown the pool whilst it is in use. Only, we don't want
51      * to delay shutdown just because some greedy user has got a connection active. Shutdown should be
52      * relatively immediate. So we don't ask for a read lock for the whole time that a connection is active.
53      */

54     private WriterPreferenceReadWriteLock primaryReadWriteLock = new WriterPreferenceReadWriteLock();
55
56     private static final String JavaDoc[] STATUS_DESCRIPTIONS = {"NULL", "AVAILABLE", "ACTIVE", "OFFLINE"};
57
58     private static final String JavaDoc MSG_MAX_CONNECTION_COUNT =
59             "Couldn't get connection because we are at maximum connection count and there are none available";
60
61     /** This is the pool itself */
62     private List JavaDoc proxyConnections;
63
64     /** This is the "round robin" that makes sure we use all the connections */
65     private int nextAvailableConnection = 0;
66
67     private long connectionsServedCount = 0;
68
69     private long connectionsRefusedCount = 0;
70
71     /** This keeps a count of how many connections there are in each state */
72     private int[] connectionCountByState = new int[4];
73
74     private ConnectionPoolDefinition definition;
75
76     private CompositeConnectionListener compositeConnectionListener = new CompositeConnectionListener();
77
78     private CompositeStateListener compositeStateListener = new CompositeStateListener();
79
80     private long timeOfLastRefusal = 0;
81
82     private int upState;
83
84     private static boolean loggedLegend;
85
86     private Admin admin;
87
88     private boolean locked = false;
89
90     private Date JavaDoc dateStarted = new Date JavaDoc();
91
92     private boolean connectionPoolUp = false;
93
94     /**
95      * This gets set during {@link #shutdown}. We use it to notify shutdown
96      * that all connections are now non-active.
97      */

98     private Thread JavaDoc shutdownThread;
99
100     private Prototyper prototyper;
101
102     /**
103      * Initialised in {@link ConnectionPool#ConnectionPool constructor}.
104      */

105     private ConnectionResetter connectionResetter;
106
107     private ConnectionValidatorIF connectionValidator;
108     
109     
110     protected ConnectionPool(ConnectionPoolDefinition definition) throws ProxoolException {
111
112         // Use the FastArrayList for performance and thread safe
113
// behaviour. We set its behaviour to "fast" (meaning reads are
114
// unsynchronized, whilst writes are not).
115
FastArrayList fal = new FastArrayList();
116         fal.setFast(true);
117         proxyConnections = fal;
118
119         log = LogFactory.getLog("org.logicalcobwebs.proxool." + definition.getAlias());
120         connectionResetter = new ConnectionResetter(log, definition.getDriver());
121         setDefinition(definition);
122
123         connectionValidator = new DefaultConnectionValidator();
124         
125         if (definition.getStatistics() != null) {
126             try {
127                 admin = new Admin(definition);
128             } catch (ProxoolException e) {
129                 log.error("Failed to initialise statistics", e);
130             }
131         }
132
133         ShutdownHook.init();
134     }
135
136     /** Starts up house keeping and prototyper threads. */
137     protected void start() throws ProxoolException {
138         connectionPoolUp = true;
139         prototyper = new Prototyper(this);
140         HouseKeeperController.register(this);
141     }
142
143     /**
144      * Get a connection from the pool. If none are available or there was an Exception
145      * then an exception is thrown and something written to the log
146      */

147     protected Connection JavaDoc getConnection() throws SQLException JavaDoc {
148
149         String JavaDoc requester = Thread.currentThread().getName();
150
151         /*
152          *If we're busy, we need to return as quickly as possible. Because this is unsynchronized
153          * we run the risk of refusing a connection when we might actually be able to. But that will
154          * only happen when we're right at or near maximum connections anyway.
155          */

156
157         try {
158             prototyper.quickRefuse();
159         } catch (SQLException JavaDoc e) {
160             connectionsRefusedCount++;
161             if (admin != null) {
162                 admin.connectionRefused();
163             }
164             log.info(displayStatistics() + " - " + MSG_MAX_CONNECTION_COUNT);
165             timeOfLastRefusal = System.currentTimeMillis();
166             setUpState(StateListenerIF.STATE_OVERLOADED);
167             throw e;
168         }
169
170         prototyper.checkSimultaneousBuildThrottle();
171         
172         ProxyConnection proxyConnection = null;
173
174         try {
175
176             // We need to look at all the connections, but we don't want to keep looping round forever
177
for (int connectionsTried = 0; connectionsTried < proxyConnections.size(); connectionsTried++) {
178                 // By doing this in a try/catch we avoid needing to synch on the size(). We need to do be
179
// able to cope with connections being removed whilst we are going round this loop
180
try {
181                     proxyConnection = (ProxyConnection) proxyConnections.get(nextAvailableConnection);
182                 } catch (ArrayIndexOutOfBoundsException JavaDoc e) {
183                     // This is thrown by a Vector (which we no longer use), but is
184
// kept here for a while.
185
nextAvailableConnection = 0;
186                     proxyConnection = (ProxyConnection) proxyConnections.get(nextAvailableConnection);
187                 } catch (IndexOutOfBoundsException JavaDoc e) {
188                     // This is thrown by a true List
189
nextAvailableConnection = 0;
190                     proxyConnection = (ProxyConnection) proxyConnections.get(nextAvailableConnection);
191                 }
192                 // setActive() returns false if the ProxyConnection wasn't available. You
193
// can't set it active twice (at least, not without making it available again
194
// in between)
195
if (proxyConnection != null && proxyConnection.setStatus(ProxyConnectionIF.STATUS_AVAILABLE, ProxyConnectionIF.STATUS_ACTIVE)) {
196
197                     // Okay. So we have it. But is it working ok?
198
if (getDefinition().isTestBeforeUse()) {
199                         if (!testConnection(proxyConnection)) {
200                             // Oops. No it's not. Let's choose another.
201
proxyConnection = null;
202                         }
203                     }
204                     if (proxyConnection != null) {
205                         nextAvailableConnection++;
206                         break;
207                     }
208                 } else {
209                     proxyConnection = null;
210                 }
211                 nextAvailableConnection++;
212             }
213             // Did we get one?
214
if (proxyConnection == null) {
215                 try {
216                     // No! Let's see if we can create one
217
proxyConnection = prototyper.buildConnection(ProxyConnection.STATUS_ACTIVE, "on demand");
218                     
219                     // Okay. So we have it. But is it working ok?
220
if (getDefinition().isTestBeforeUse()) {
221                         if (!testConnection(proxyConnection)) {
222                             // Oops. No it's not. There's not much more we can do for now
223
throw new SQLException JavaDoc("Created a new connection but it failed its test");
224                         }
225                     }
226                 } catch (SQLException JavaDoc e) {
227                     throw e;
228                 } catch (ProxoolException e) {
229                     log.debug("Couldn't get connection", e);
230                     throw new SQLException JavaDoc(e.toString());
231                 } catch (Throwable JavaDoc e) {
232                     log.error("Couldn't get connection", e);
233                     throw new SQLException JavaDoc(e.toString());
234                 }
235             }
236
237         } catch (SQLException JavaDoc e) {
238             throw e;
239         } catch (Throwable JavaDoc t) {
240             log.error("Problem getting connection", t);
241             throw new SQLException JavaDoc(t.toString());
242         } finally {
243             if (proxyConnection != null) {
244                 connectionsServedCount++;
245                 proxyConnection.setRequester(requester);
246             } else {
247                 connectionsRefusedCount++;
248                 if (admin != null) {
249                     admin.connectionRefused();
250                 }
251                 timeOfLastRefusal = System.currentTimeMillis();
252                 setUpState(StateListenerIF.STATE_OVERLOADED);
253             }
254         }
255
256         if (proxyConnection == null) {
257             throw new SQLException JavaDoc("Unknown reason for not getting connection. Sorry.");
258         }
259
260         if (log.isDebugEnabled() && getDefinition().isVerbose()) {
261             log.debug(displayStatistics() + " - Connection #" + proxyConnection.getId() + " served");
262         }
263
264         // This gives the proxy connection a chance to reset itself before it is served.
265
proxyConnection.open();
266
267         return ProxyFactory.getWrappedConnection(proxyConnection);
268     }
269
270     /**
271      * Test the connection (if required)
272      * If the connection fails the test, it is removed from the pool.
273      * If no ConnectionValidatorIF is defined, then the test always succeed.
274      *
275      * @param proxyConnection the connection to test
276      * @return TRUE if the connection pass the test, FALSE if it fails
277      */

278     private boolean testConnection(ProxyConnectionIF proxyConnection) {
279         // is validation enabled ?
280
if( connectionValidator == null ) {
281             return true;
282         }
283         
284         // validate the connection
285
boolean success = connectionValidator.validate(getDefinition(), proxyConnection.getConnection());
286         
287         if( success ) {
288             if (LOG.isDebugEnabled()) {
289                 LOG.debug(displayStatistics() + " - Connection #" + proxyConnection.getId() + " tested: OK");
290             }
291         }
292         else {
293             proxyConnection.setStatus(ProxyConnectionIF.STATUS_NULL);
294             removeProxyConnection(proxyConnection, "it didn't pass the validation", ConnectionPool.REQUEST_EXPIRY, true);
295         }
296         
297         // return
298
return success;
299     }
300
301     /**
302      * Add a ProxyConnection to the pool
303      * @param proxyConnection new connection
304      * @return true if the connection was added or false if it wasn't (for instance, if the definition it
305      * was built with is out of date).
306      */

307     protected boolean addProxyConnection(ProxyConnectionIF proxyConnection) {
308         boolean added = false;
309         try {
310             acquireConnectionStatusWriteLock();
311             if (proxyConnection.getDefinition() == getDefinition()) {
312                 proxyConnections.add(proxyConnection);
313                 connectionCountByState[proxyConnection.getStatus()]++;
314                 added = true;
315             }
316         } finally {
317             releaseConnectionStatusWriteLock();
318         }
319         return added;
320     }
321
322     protected static String JavaDoc getStatusDescription(int status) {
323         try {
324             return STATUS_DESCRIPTIONS[status];
325         } catch (ArrayIndexOutOfBoundsException JavaDoc e) {
326             return "Unknown status: " + status;
327         }
328     }
329
330     /**
331      * When you have finished with a Connection you should put it back here. That will make it available to others.
332      * Unless it's due for expiry, in which case it will... expire
333      */

334     protected void putConnection(ProxyConnectionIF proxyConnection) {
335       
336         if (admin != null) {
337             long now = System.currentTimeMillis();
338             long start = proxyConnection.getTimeLastStartActive();
339             if (now - start < 0) {
340                 log.warn("Future start time detected. #" + proxyConnection.getId() + " start = " + new Date JavaDoc(start)
341                         + " (" + (now - start) + " milliseconds)");
342             } else if (now - start > 1000000) {
343                 log.warn("Suspiciously long active time. #" + proxyConnection.getId() + " start = " + new Date JavaDoc(start));
344             }
345             admin.connectionReturned(now - start);
346         }
347
348         // It's possible that this connection is due for expiry
349
if (proxyConnection.isMarkedForExpiry()) {
350             if (proxyConnection.setStatus(ProxyConnectionIF.STATUS_ACTIVE, ProxyConnectionIF.STATUS_NULL)) {
351                 expireProxyConnection(proxyConnection, proxyConnection.getReasonForMark(), REQUEST_EXPIRY);
352             }
353         } else {
354
355             // Optionally, test it to see if it is ok
356
if (getDefinition().isTestAfterUse()) {
357                 // It will get removed by this call if it is no good
358
testConnection(proxyConnection);
359             }
360
361             // Let's make it available for someone else
362
if (!proxyConnection.setStatus(ProxyConnectionIF.STATUS_ACTIVE, ProxyConnectionIF.STATUS_AVAILABLE)) {
363                 if (proxyConnection.getStatus() == ProxyConnectionIF.STATUS_AVAILABLE) {
364                     // This is *probably* because the connection has been closed twice.
365
// Although we can't tell for sure. We'll have to refactor this to use
366
// throw away wrappers to avoid this problem.
367
log.warn("Unable to close connection " + proxyConnection.getId()
368                             + " - I suspect that it has been closed already. Closing it more"
369                             + " than once is unwise and should be avoided.");
370                 } else {
371                     log.warn("Unable to set status of connection " + proxyConnection.getId()
372                             + " from " + getStatusDescription(ProxyConnectionIF.STATUS_ACTIVE)
373                             + " to " + getStatusDescription(ProxyConnectionIF.STATUS_AVAILABLE)
374                             + " because it's state was " + getStatusDescription(proxyConnection.getStatus()));
375                 }
376             }
377         }
378
379         if (log.isDebugEnabled() && getDefinition().isVerbose()) {
380             log.debug(displayStatistics() + " - Connection #" + proxyConnection.getId() + " returned (now "
381                     + getStatusDescription(proxyConnection.getStatus()) + ")");
382         }
383
384     }
385
386     /** This means that there's something wrong the connection and it's probably best if no one uses it again. */
387     protected void throwConnection(ProxyConnectionIF proxyConnection, String JavaDoc reason) {
388         expireConnectionAsSoonAsPossible(proxyConnection, reason, true);
389     }
390
391     /** Get a ProxyConnection by index */
392     private ProxyConnectionIF getProxyConnection(int i) {
393         return (ProxyConnectionIF) proxyConnections.get(i);
394     }
395
396     /**
397      * Return an array of all the connections
398      * @return array of connections
399      */

400     protected ProxyConnectionIF[] getProxyConnections() {
401         return (ProxyConnectionIF[]) proxyConnections.toArray(new ProxyConnectionIF[proxyConnections.size()]);
402     }
403
404     /**
405      * Remove a ProxyConnection by calling its {@link ConnectionListenerIF#onDeath onDeath} event,
406      * closing it (for real) and then removing it from the list.
407      * @param proxyConnection the connection to remove
408      * @param reason for log audit
409      * @param forceExpiry true means close now, whether it is active or not; false means if it is active then
410      * merely mark it for expiry so that it is removed as soon as it finished being active
411      * @param triggerSweep if true then this removal will trigger a prototype sweep
412      */

413     protected void removeProxyConnection(ProxyConnectionIF proxyConnection, String JavaDoc reason, boolean forceExpiry, boolean triggerSweep) {
414         // Just check that it is null
415
if (forceExpiry || proxyConnection.isNull()) {
416
417             proxyConnection.setStatus(ProxyConnectionIF.STATUS_NULL);
418
419             /* Run some code everytime we destroy a connection */
420
421             try {
422                 onDeath(proxyConnection.getConnection());
423             } catch (SQLException JavaDoc e) {
424                 log.error("Problem during onDeath (ignored)", e);
425             }
426
427             // The reallyClose() method also decrements the connectionCount.
428
try {
429                 proxyConnection.reallyClose();
430             } catch (SQLException JavaDoc e) {
431                 log.error(e);
432             }
433
434             try {
435                 // If we're shutting down then getting a write lock will cause a deadlock
436
if (isConnectionPoolUp()) {
437                     acquireConnectionStatusWriteLock();
438                 }
439                 proxyConnections.remove(proxyConnection);
440             } finally {
441                 if (isConnectionPoolUp()) {
442                     releaseConnectionStatusWriteLock();
443                 }
444             }
445
446             if (log.isDebugEnabled()) {
447                 log.debug(displayStatistics() + " - #" + FormatHelper.formatMediumNumber(proxyConnection.getId())
448                         + " removed because " + reason + ".");
449             }
450
451             if (triggerSweep) {
452                 PrototyperController.triggerSweep(getDefinition().getAlias());
453             }
454
455         } else {
456             log.error(displayStatistics() + " - #" + FormatHelper.formatMediumNumber(proxyConnection.getId())
457                     + " was not removed because isNull() was false.");
458         }
459     }
460
461     protected void expireProxyConnection(ProxyConnectionIF proxyConnection, String JavaDoc reason, boolean forceExpiry) {
462         removeProxyConnection(proxyConnection, reason, forceExpiry, true);
463     }
464
465     /**
466      * Call this to shutdown gracefully.
467      * @param delay how long to wait for connections to become free before forcing them to close anyway
468      */

469     protected void shutdown(int delay, String JavaDoc finalizerName) throws Throwable JavaDoc {
470
471         final String JavaDoc alias = getDefinition().getAlias();
472         try {
473             /* This will stop us giving out any more connections and may
474             cause some of the threads to die. */

475
476             acquirePrimaryWriteLock();
477
478             if (connectionPoolUp) {
479
480                 connectionPoolUp = false;
481                 long startFinalize = System.currentTimeMillis();
482                 shutdownThread = Thread.currentThread();
483
484                 if (delay > 0) {
485                     log.info("Shutting down '" + alias + "' pool started at "
486                             + dateStarted + " - waiting for " + delay
487                             + " milliseconds for everything to stop. [ "
488                             + finalizerName + "]");
489                 } else {
490                     log.info("Shutting down '" + alias + "' pool immediately [" + finalizerName + "]");
491                 }
492
493                 /* Interrupt the threads (in case they're sleeping) */
494
495                 boolean connectionClosedManually = false;
496                 try {
497
498                     try {
499                         HouseKeeperController.cancel(alias);
500                     } catch (ProxoolException e) {
501                         log.error("Shutdown couldn't cancel house keeper", e);
502                     }
503
504                     // Cancel the admin thread (for statistics)
505
if (admin != null) {
506                         admin.cancelAll();
507                     }
508
509                     /* Patience, patience. */
510
511                     if (connectionCountByState[ProxyConnectionIF.STATUS_ACTIVE] != 0) {
512                         long endWait = startFinalize + delay;
513                         LOG.info("Waiting until " + new Date JavaDoc(endWait) + " for all connections to become inactive (active count is "
514                                 + connectionCountByState[ProxyConnectionIF.STATUS_ACTIVE] + ").");
515                         while (true) {
516                             long timeout = endWait - System.currentTimeMillis();
517                             if (timeout > 0) {
518                                 synchronized (Thread.currentThread()) {
519                                     try {
520                                         Thread.currentThread().wait(timeout);
521                                     } catch (InterruptedException JavaDoc e) {
522                                         log.debug("Interrupted whilst sleeping.");
523                                     }
524                                 }
525                             }
526                             int activeCount = connectionCountByState[ProxyConnectionIF.STATUS_ACTIVE];
527                             if (activeCount == 0) {
528                                 break;
529                             }
530                             if (System.currentTimeMillis() < endWait) {
531                                 LOG.info("Still waiting for active count to reach zero (currently " + activeCount + ").");
532                             } else {
533                                 // There are still connections active. Oh well, we're not _that_ patient
534
LOG.warn("Shutdown waited for "
535                                         + (System.currentTimeMillis() - startFinalize) + " milliseconds for all "
536                                         + "the connections to become inactive but the active count is still "
537                                         + activeCount + ". Shutting down anyway.");
538                                 break;
539                             }
540                             Thread.sleep(100);
541                         }
542                     }
543
544                     prototyper.cancel();
545                     
546                     // Silently close all connections
547
for (int i = proxyConnections.size() - 1; i >= 0; i--) {
548                         long id = getProxyConnection(i).getId();
549                         try {
550                             connectionClosedManually = true;
551                             removeProxyConnection(getProxyConnection(i), "of shutdown", true, false);
552                             if (log.isDebugEnabled()) {
553                                 log.debug("Connection #" + id + " closed");
554                             }
555                         } catch (Throwable JavaDoc t) {
556                             if (log.isDebugEnabled()) {
557                                 log.debug("Problem closing connection #" + id, t);
558                             }
559
560                         }
561                     }
562
563                 } catch (Throwable JavaDoc t) {
564                     log.error("Unknown problem finalizing pool", t);
565                 } finally {
566
567                     ConnectionPoolManager.getInstance().removeConnectionPool(alias);
568
569                     if (log.isDebugEnabled()) {
570                         log.info("'" + alias + "' pool has been closed down by " + finalizerName
571                                 + " in " + (System.currentTimeMillis() - startFinalize) + " milliseconds.");
572                         if (!connectionClosedManually) {
573                             log.debug("No connections required manual removal.");
574                         }
575                     }
576                     super.finalize();
577                 }
578             } else {
579                 if (log.isDebugEnabled()) {
580                     log.debug("Ignoring duplicate attempt to shutdown '" + alias + "' pool by " + finalizerName);
581                 }
582             }
583         } catch (Throwable JavaDoc t) {
584             log.error(finalizerName + " couldn't shutdown pool", t);
585         } finally {
586             releasePrimaryWriteLock();
587         }
588     }
589
590     /**
591      * You should {@link #acquireConnectionStatusReadLock acquire}
592      * a read lock if you want this to be accurate (but that might have
593      * an impact on the performance of your pool).
594      * @see ConnectionPoolStatisticsIF#getAvailableConnectionCount
595      */

596     public int getAvailableConnectionCount() {
597         return connectionCountByState[ConnectionInfoIF.STATUS_AVAILABLE];
598     }
599
600     /**
601      * You should {@link #acquireConnectionStatusReadLock acquire}
602      * a read lock if you want this to be accurate (but that might have
603      * an impact on the performance of your pool).
604      * @see ConnectionPoolStatisticsIF#getActiveConnectionCount
605      */

606     public int getActiveConnectionCount() {
607         return connectionCountByState[ConnectionInfoIF.STATUS_ACTIVE];
608     }
609
610     /**
611      * You should {@link #acquireConnectionStatusReadLock acquire}
612      * a read lock if you want this to be accurate (but that might have
613      * an impact on the performance of your pool).
614      * @see ConnectionPoolStatisticsIF#getOfflineConnectionCount
615      */

616     public int getOfflineConnectionCount() {
617         return connectionCountByState[ConnectionInfoIF.STATUS_OFFLINE];
618     }
619
620     protected String JavaDoc displayStatistics() {
621
622         if (!loggedLegend) {
623             log.info("Proxool statistics legend: \"s - r (a/t/o)\" > s=served, r=refused (only shown if non-zero), a=active, t=total, o=offline (being tested)");
624             loggedLegend = true;
625         }
626
627         StringBuffer JavaDoc statistics = new StringBuffer JavaDoc();
628         statistics.append(FormatHelper.formatBigNumber(getConnectionsServedCount()));
629
630         if (getConnectionsRefusedCount() > 0) {
631             statistics.append(" -");
632             statistics.append(FormatHelper.formatBigNumber(getConnectionsRefusedCount()));
633         }
634
635         statistics.append(" (");
636         statistics.append(FormatHelper.formatSmallNumber(getActiveConnectionCount()));
637         statistics.append("/");
638         statistics.append(FormatHelper.formatSmallNumber(getAvailableConnectionCount() + getActiveConnectionCount()));
639         statistics.append("/");
640         statistics.append(FormatHelper.formatSmallNumber(getOfflineConnectionCount()));
641         statistics.append(")");
642
643         // Don't need this triple check any more.
644
/*
645         if (getDefinition().getDebugLevel() == ConnectionPoolDefinitionIF.DEBUG_LEVEL_LOUD) {
646             statistics.append(", cc=");
647             statistics.append(connectionCount);
648             statistics.append(", ccc=");
649             statistics.append(connectedConnectionCount);
650         }
651         */

652
653         return statistics.toString();
654     }
655
656     protected void expireAllConnections(String JavaDoc reason, boolean merciful) {
657
658         // Do this in two stages because expiring a connection will trigger
659
// the prototyper to make more. And that might mean we end up
660
// killing a newly made connection;
661
Set JavaDoc pcs = new HashSet JavaDoc();
662         for (int i = proxyConnections.size() - 1; i >= 0; i--) {
663             pcs.add(proxyConnections.get(i));
664         }
665
666         Iterator JavaDoc i = pcs.iterator();
667         while (i.hasNext()) {
668             ProxyConnectionIF pc = (ProxyConnectionIF) i.next();
669             expireConnectionAsSoonAsPossible(pc, reason, merciful);
670         }
671     }
672
673     protected void expireConnectionAsSoonAsPossible(ProxyConnectionIF proxyConnection, String JavaDoc reason, boolean merciful) {
674         if (proxyConnection.setStatus(ProxyConnectionIF.STATUS_AVAILABLE, ProxyConnectionIF.STATUS_OFFLINE)) {
675             if (proxyConnection.setStatus(ProxyConnectionIF.STATUS_OFFLINE, ProxyConnectionIF.STATUS_NULL)) {
676                 // It is. Expire it now .
677
expireProxyConnection(proxyConnection, reason, REQUEST_EXPIRY);
678             }
679         } else {
680             // Oh no, it's in use.
681

682             if (merciful) {
683                 //Never mind, we'll mark it for expiry
684
// next time it is available. This will happen in the
685
// putConnection() method.
686
proxyConnection.markForExpiry(reason);
687                 if (log.isDebugEnabled()) {
688                     log.debug(displayStatistics() + " - #" + FormatHelper.formatMediumNumber(proxyConnection.getId()) + " marked for expiry.");
689                 }
690             } else {
691                 // So? Kill, kill, kill
692

693                 // We have to make sure it's null first.
694
expireProxyConnection(proxyConnection, reason, FORCE_EXPIRY);
695             }
696
697         } // END if (proxyConnection.setOffline())
698
}
699
700     protected void registerRemovedConnection(int status) {
701         prototyper.connectionRemoved();
702         connectionCountByState[status]--;
703     }
704
705     /**
706      * You should {@link #acquireConnectionStatusWriteLock acquire} a write lock
707      * before calling this method
708      * @param oldStatus so we know which count to decrement
709      * @param newStatus so we know which count to increment
710      */

711     protected void changeStatus(int oldStatus, int newStatus) {
712         // LOG.debug("About to change status");
713
connectionCountByState[oldStatus]--;
714         connectionCountByState[newStatus]++;
715         // LOG.debug("Changing status from " + oldStatus + " to " + newStatus);
716
// Check to see if shutdown is waiting for all connections to become
717
// non-active
718
if (shutdownThread != null && connectionCountByState[ProxyConnectionIF.STATUS_ACTIVE] == 0) {
719             synchronized (shutdownThread) {
720                 shutdownThread.notify();
721             }
722         }
723
724     }
725
726     public long getConnectionsServedCount() {
727         return connectionsServedCount;
728     }
729
730     public long getConnectionsRefusedCount() {
731         return connectionsRefusedCount;
732     }
733
734     protected ConnectionPoolDefinition getDefinition() {
735         return definition;
736     }
737
738     /**
739      * Changes both the way that any new connections will be made, and the behaviour of the pool. Consider
740      * calling expireAllConnections() if you're in a hurry.
741      */

742     protected synchronized void setDefinition(ConnectionPoolDefinition definition) throws ProxoolException {
743         this.definition = definition;
744
745         try {
746             Class.forName(definition.getDriver());
747         } catch (ClassNotFoundException JavaDoc e) {
748             log.error("Couldn't load class " + definition.getDriver(), e);
749             throw new ProxoolException("Couldn't load class " + definition.getDriver());
750         } catch (NullPointerException JavaDoc e) {
751             log.error("Definition did not contain driver", e);
752             throw new ProxoolException("Definition did not contain driver");
753         }
754
755     }
756
757     /**
758      * @deprecated use {@link #addStateListener(StateListenerIF)} instead.
759      */

760     public void setStateListener(StateListenerIF stateListener) {
761         addStateListener(stateListener);
762     }
763
764     public void addStateListener(StateListenerIF stateListener) {
765         this.compositeStateListener.addListener(stateListener);
766     }
767
768     public boolean removeStateListener(StateListenerIF stateListener) {
769         return this.compositeStateListener.removeListener(stateListener);
770     }
771
772     /**
773      * @deprecated use {@link #addConnectionListener(ConnectionListenerIF)} instead.
774      */

775     public void setConnectionListener(ConnectionListenerIF connectionListener) {
776         addConnectionListener(connectionListener);
777     }
778
779     public void addConnectionListener(ConnectionListenerIF connectionListener) {
780         this.compositeConnectionListener.addListener(connectionListener);
781     }
782
783     public boolean removeConnectionListener(ConnectionListenerIF connectionListener) {
784         return this.compositeConnectionListener.removeListener(connectionListener);
785     }
786
787     /** Call the onBirth() method on each StateListenerIF . */
788     protected void onBirth(Connection JavaDoc connection) throws SQLException JavaDoc {
789         this.compositeConnectionListener.onBirth(connection);
790     }
791
792     /** Call the onDeath() method on each StateListenerIF . */
793     protected void onDeath(Connection JavaDoc connection) throws SQLException JavaDoc {
794         this.compositeConnectionListener.onDeath(connection);
795     }
796
797     /** Call the onExecute() method on each StateListenerIF . */
798     protected void onExecute(String JavaDoc command, long elapsedTime, Exception JavaDoc exception) throws SQLException JavaDoc {
799         if (exception == null) {
800             this.compositeConnectionListener.onExecute(command, elapsedTime);
801         } else {
802             this.compositeConnectionListener.onFail(command, exception);
803         }
804     }
805
806     /**
807      * Is there a {@link ConnectionListenerIF listener} for connections
808      * @return true if there is a listener registered.
809      */

810     protected boolean isConnectionListenedTo() {
811         return !compositeConnectionListener.isEmpty();
812     }
813
814     public String JavaDoc toString() {
815         return getDefinition().toString();
816     }
817
818     public int getUpState() {
819         return upState;
820     }
821
822
823     public void setUpState(int upState) {
824         if (this.upState != upState) {
825             compositeStateListener.upStateChanged(upState);
826             this.upState = upState;
827         }
828     }
829
830     protected Collection JavaDoc getConnectionInfos() {
831         Collection JavaDoc cis = null;
832         cis = new TreeSet JavaDoc();
833         Iterator JavaDoc i = proxyConnections.iterator();
834         while (i.hasNext()) {
835             ConnectionInfoIF connectionInfo = (ConnectionInfoIF) i.next();
836             ConnectionInfo ci = new ConnectionInfo();
837             ci.setAge(connectionInfo.getAge());
838             ci.setBirthDate(connectionInfo.getBirthDate());
839             ci.setId(connectionInfo.getId());
840             ci.setMark(connectionInfo.getMark());
841             ci.setRequester(connectionInfo.getRequester());
842             ci.setStatus(connectionInfo.getStatus());
843             ci.setTimeLastStartActive(connectionInfo.getTimeLastStartActive());
844             ci.setTimeLastStopActive(connectionInfo.getTimeLastStopActive());
845             ci.setDelegateUrl(connectionInfo.getDelegateUrl());
846             ci.setProxyHashcode(connectionInfo.getProxyHashcode());
847             ci.setDelegateHashcode(connectionInfo.getDelegateHashcode());
848             String JavaDoc[] sqlCalls = connectionInfo.getSqlCalls();
849             for (int j = 0; j < sqlCalls.length; j++) {
850                 ci.addSqlCall(sqlCalls[j]);
851             }
852             cis.add(ci);
853         }
854         return cis;
855     }
856
857     /**
858      * Manually expire a connection.
859      * @param id the id of the connection to kill
860      * @param forceExpiry use true to expire even if it is in use
861      * @return true if the connection was found and expired, else false
862      */

863     public boolean expireConnection(long id, boolean forceExpiry) {
864         boolean success = false;
865         ProxyConnection proxyConnection = null;
866
867         // We need to look at all the connections, but we don't want to keep looping round forever
868
for (int connectionsTried = 0; connectionsTried < proxyConnections.size(); connectionsTried++) {
869             // By doing this in a try/catch we avoid needing to synch on the size(). We need to do be
870
// able to cope with connections being removed whilst we are going round this loop
871
try {
872                 proxyConnection = (ProxyConnection) proxyConnections.get(nextAvailableConnection);
873             } catch (IndexOutOfBoundsException JavaDoc e) {
874                 nextAvailableConnection = 0;
875                 proxyConnection = (ProxyConnection) proxyConnections.get(nextAvailableConnection);
876             }
877
878             if (proxyConnection.getId() == id) {
879                 // This is the one
880
proxyConnection.setStatus(ProxyConnectionIF.STATUS_AVAILABLE, ProxyConnectionIF.STATUS_OFFLINE);
881                 proxyConnection.setStatus(ProxyConnectionIF.STATUS_OFFLINE, ProxyConnectionIF.STATUS_NULL);
882                 removeProxyConnection(proxyConnection, "it was manually killed", forceExpiry, true);
883                 success = true;
884                 break;
885             }
886
887             nextAvailableConnection++;
888         }
889
890         if (!success) {
891             if (log.isDebugEnabled()) {
892                 log.debug(displayStatistics() + " - couldn't find " + FormatHelper.formatMediumNumber(proxyConnection.getId())
893                         + " and I've just been asked to expire it");
894             }
895         }
896
897         return success;
898     }
899
900     public Log getLog() {
901         return log;
902     }
903
904     /**
905      * {@link ConnectionResetter#initialise Initialises} the ConnectionResetter.
906      * @param connection sample Connection to use for default values
907      */

908     protected void initialiseConnectionResetter(Connection JavaDoc connection) {
909         connectionResetter.initialise(connection);
910     }
911
912     /**
913      * {@link ConnectionResetter#reset Resets} a Connection to its
914      * original state.
915      * @param connection the one to reset
916      */

917     protected boolean resetConnection(Connection JavaDoc connection, String JavaDoc id) {
918         return connectionResetter.reset(connection, id);
919     }
920
921     /**
922      * @see ConnectionPoolStatisticsIF#getDateStarted
923      */

924     public Date JavaDoc getDateStarted() {
925         return dateStarted;
926     }
927
928     /**
929      * Get the admin for this pool
930      * @return admin
931      */

932     protected Admin getAdmin() {
933         return admin;
934     }
935
936     protected boolean isLocked() {
937         return locked;
938     }
939
940     protected void lock() {
941         locked = true;
942     }
943
944     protected void unlock() {
945         locked = false;
946     }
947
948     /**
949      * Call this if you want to do something important to the pool. Like shut it down.
950      * @throws InterruptedException if we couldn't
951      */

952     protected void acquirePrimaryReadLock() throws InterruptedException JavaDoc {
953 // if (log.isDebugEnabled()) {
954
// try {
955
// throw new RuntimeException("TRACE ONLY");
956
// } catch (RuntimeException e) {
957
// log.debug("About to acquire primary read lock", e);
958
// }
959
// // log.debug("About to acquire primary read lock");
960
// }
961
primaryReadWriteLock.readLock().acquire();
962 // if (log.isDebugEnabled()) {
963
// try {
964
// throw new RuntimeException("TRACE ONLY");
965
// } catch (RuntimeException e) {
966
// log.debug("Acquired primary read lock", e);
967
// }
968
// //log.debug("Acquired primary read lock");
969
// }
970
}
971
972     /**
973      * @see #acquirePrimaryReadLock
974      */

975     protected void releasePrimaryReadLock() {
976 // try {
977
// throw new RuntimeException("TRACE ONLY");
978
// } catch (RuntimeException e) {
979
// log.debug("Released primary read lock", e);
980
// }
981
//log.debug("Released primary read lock");
982
primaryReadWriteLock.readLock().release();
983     }
984
985     /**
986      * Call this everytime you build a connection. It ensures that we're not
987      * trying to shutdown the pool whilst we are building a connection. So you
988      * should check that the pool is still {@link #isConnectionPoolUp up}.
989      * @throws InterruptedException if there was a problem.
990      */

991     protected void acquirePrimaryWriteLock() throws InterruptedException JavaDoc {
992 // boolean success = false;
993
// try {
994
// if (log.isDebugEnabled()) {
995
// try {
996
// throw new RuntimeException("TRACE ONLY");
997
// } catch (RuntimeException e) {
998
// log.debug("About to acquire primary write lock", e);
999
// }
1000
// //log.debug("About to acquire primary write lock");
1001
// }
1002
primaryReadWriteLock.writeLock().acquire();
1003// success = true;
1004
// if (log.isDebugEnabled()) {
1005
// try {
1006
// throw new RuntimeException("TRACE ONLY");
1007
// } catch (RuntimeException e) {
1008
// log.debug("Acquired primary write lock", e);
1009
// }
1010
// //log.debug("Acquired primary write lock");
1011
// }
1012
// } finally {
1013
// if (log.isDebugEnabled() && !success) {
1014
// try {
1015
// throw new RuntimeException("TRACE ONLY");
1016
// } catch (RuntimeException e) {
1017
// log.debug("Failed to acquire primary write lock", e);
1018
// }
1019
// //log.debug("Failed to acquire primary write lock");
1020
// }
1021
// }
1022
}
1023
1024    /**
1025     * @see #acquirePrimaryReadLock
1026     */

1027    protected void releasePrimaryWriteLock() {
1028        primaryReadWriteLock.writeLock().release();
1029// try {
1030
// throw new RuntimeException("TRACE ONLY");
1031
// } catch (RuntimeException e) {
1032
// log.debug("Released primary write lock", e);
1033
// }
1034
//log.debug("Released primary write lock");
1035
}
1036
1037    /**
1038     * Is the pool up?
1039     * @return false is the connection pool has been {@link #shutdown shutdown}
1040     * (or is in the process of being shutdown).
1041     */

1042    protected boolean isConnectionPoolUp() {
1043        return connectionPoolUp;
1044    }
1045
1046    protected static final boolean FORCE_EXPIRY = true;
1047
1048    protected static final boolean REQUEST_EXPIRY = false;
1049
1050    /**
1051     * The time (in milliseconds) that we last refused a connection
1052     * @return timeOfLastRefusal
1053     */

1054    protected long getTimeOfLastRefusal() {
1055        return timeOfLastRefusal;
1056    }
1057
1058    protected void acquireConnectionStatusWriteLock() {
1059        try {
1060// try {
1061
// throw new RuntimeException("TRACE ONLY");
1062
// } catch (RuntimeException e) {
1063
// LOG.debug("About to acquire connectionStatus write lock", e);
1064
// }
1065
connectionStatusReadWriteLock.writeLock().acquire();
1066// try {
1067
// throw new RuntimeException("TRACE ONLY");
1068
// } catch (RuntimeException e) {
1069
// LOG.debug("Acquired connectionStatus write lock", e);
1070
// }
1071
} catch (InterruptedException JavaDoc e) {
1072            log.error("Couldn't acquire connectionStatus write lock", e);
1073        }
1074    }
1075
1076    protected void releaseConnectionStatusWriteLock() {
1077        connectionStatusReadWriteLock.writeLock().release();
1078// try {
1079
// throw new RuntimeException("TRACE ONLY");
1080
// } catch (RuntimeException e) {
1081
// LOG.debug("Released connectionStatus write lock", e);
1082
// }
1083
}
1084
1085    protected void acquireConnectionStatusReadLock() {
1086        try {
1087            connectionStatusReadWriteLock.readLock().acquire();
1088        } catch (InterruptedException JavaDoc e) {
1089            log.error("Couldn't acquire connectionStatus read lock", e);
1090        }
1091    }
1092
1093    protected boolean attemptConnectionStatusReadLock(long msecs) {
1094        try {
1095            return connectionStatusReadWriteLock.readLock().attempt(msecs);
1096        } catch (InterruptedException JavaDoc e) {
1097            log.error("Couldn't acquire connectionStatus read lock", e);
1098            return false;
1099        }
1100    }
1101
1102    protected void releaseConnectionStatusReadLock() {
1103        connectionStatusReadWriteLock.readLock().release();
1104// LOG.debug("Released connectionStatus read lock");
1105
}
1106
1107    protected Prototyper getPrototyper() {
1108        return prototyper;
1109    }
1110
1111    public long getConnectionCount() {
1112        return getPrototyper().getConnectionCount();
1113    }
1114}
1115
1116/*
1117 Revision history:
1118 $Log: ConnectionPool.java,v $
1119 Revision 1.84 2006/03/23 11:44:57 billhorsman
1120 More information when quickly refusing
1121
1122 Revision 1.83 2006/01/18 14:40:01 billhorsman
1123 Unbundled Jakarta's Commons Logging.
1124
1125 Revision 1.82 2005/10/07 08:19:05 billhorsman
1126 New sqlCalls gives list of SQL calls rather than just he most recent (for when a connection makes more than one call before being returned to the pool)
1127
1128 Revision 1.81 2005/10/02 12:32:02 billhorsman
1129 Make connectionCount available to statistics
1130
1131 Revision 1.80 2005/09/26 09:54:14 billhorsman
1132 Avoid suspected deadlock when getting a detailed snapshot. Only attempt to get the concurrent lock for 10 seconds before giving up.
1133
1134 Revision 1.79 2005/05/04 16:26:31 billhorsman
1135 Only add a new connection if the definition matches
1136
1137 Revision 1.78 2004/03/25 22:02:15 brenuart
1138 First step towards pluggable ConnectionBuilderIF & ConnectionValidatorIF.
1139 Include some minor refactoring that lead to deprecation of some PrototyperController methods.
1140
1141 Revision 1.76 2004/02/23 17:47:32 billhorsman
1142 Improved message that gets logged if the state change of a connection fails.
1143
1144 Revision 1.75 2004/02/23 17:38:58 billhorsman
1145 Improved message that gets logged if you close a connection more than once.
1146
1147 Revision 1.74 2004/02/12 13:02:17 billhorsman
1148 Catch correct exception when iterating through list.
1149
1150 Revision 1.73 2003/12/09 18:54:55 billhorsman
1151 Make closure of statement during connection test more robust - credit to John Hume
1152
1153 Revision 1.72 2003/11/04 13:52:01 billhorsman
1154 Fixed warning message
1155
1156 Revision 1.71 2003/10/30 00:11:15 billhorsman
1157 Debug info and error logged if unsuccessful attempt to put connection back in pool. Plus connectioninfo comparator changed
1158
1159 Revision 1.70 2003/09/30 18:39:08 billhorsman
1160 New test-before-use, test-after-use and fatal-sql-exception-wrapper-class properties.
1161
1162 Revision 1.69 2003/09/30 07:50:04 billhorsman
1163 Smarter throwing of caught SQLExceptions without wrapping them up inside another (and losing the stack trace)
1164
1165 Revision 1.68 2003/09/20 17:04:06 billhorsman
1166 Fix for incorrect OFFLINE count when house keeper removed a connection if the test SQL failed. This
1167 meant that the offline count went negative. The only consequence of that is that the logs look funny.
1168
1169 Revision 1.67 2003/08/30 14:54:04 billhorsman
1170 Checkstyle
1171
1172 Revision 1.66 2003/04/10 08:23:54 billhorsman
1173 removed very frequent debug
1174
1175 Revision 1.65 2003/03/11 23:58:04 billhorsman
1176 fixed deadlock on connection expiry
1177
1178 Revision 1.64 2003/03/11 14:51:49 billhorsman
1179 more concurrency fixes relating to snapshots
1180
1181 Revision 1.63 2003/03/11 01:16:29 billhorsman
1182 removed misleasing debug
1183
1184 Revision 1.62 2003/03/11 00:32:13 billhorsman
1185 fixed negative timeout
1186
1187 Revision 1.61 2003/03/10 23:39:51 billhorsman
1188 shutdown is now notified when active count reaches
1189 zero
1190
1191 Revision 1.60 2003/03/10 16:26:35 billhorsman
1192 removed debug traces
1193
1194 Revision 1.59 2003/03/10 15:26:44 billhorsman
1195 refactoringn of concurrency stuff (and some import
1196 optimisation)
1197
1198 Revision 1.58 2003/03/05 18:42:32 billhorsman
1199 big refactor of prototyping and house keeping to
1200 drastically reduce the number of threads when using
1201 many pools
1202
1203 Revision 1.57 2003/03/03 16:06:44 billhorsman
1204 name house keeper and prototyper threads now includes alias
1205
1206 Revision 1.56 2003/03/03 11:11:57 billhorsman
1207 fixed licence
1208
1209 Revision 1.55 2003/02/28 18:08:55 billhorsman
1210 OVERLOAD state is now triggered immediately rather
1211 than waiting for house keeper
1212
1213 Revision 1.54 2003/02/28 10:10:25 billhorsman
1214 on death now gets called for connections killed during shutdown
1215
1216 Revision 1.53 2003/02/26 16:05:52 billhorsman
1217 widespread changes caused by refactoring the way we
1218 update and redefine pool definitions.
1219
1220 Revision 1.52 2003/02/26 12:57:30 billhorsman
1221 added TO DO
1222
1223 Revision 1.51 2003/02/19 23:46:10 billhorsman
1224 renamed monitor package to admin
1225
1226 Revision 1.50 2003/02/19 23:07:46 billhorsman
1227 state changes are now only calculated every time the house
1228 keeper runs, but it's more accurate
1229
1230 Revision 1.49 2003/02/19 22:38:33 billhorsman
1231 fatal sql exception causes house keeper to run
1232 immediately
1233
1234 Revision 1.48 2003/02/18 16:49:59 chr32
1235 Added possibility to remove connection and state listeners.
1236
1237 Revision 1.47 2003/02/12 12:27:16 billhorsman
1238 log proxy hashcode too
1239
1240 Revision 1.46 2003/02/07 17:26:04 billhorsman
1241 deprecated removeAllConnectionPools in favour of
1242 shutdown (and dropped unreliable finalize() method)
1243
1244 Revision 1.45 2003/02/07 14:19:01 billhorsman
1245 fixed deprecated use of debugLevel property
1246
1247 Revision 1.44 2003/02/07 14:16:46 billhorsman
1248 support for StatisticsListenerIF
1249
1250 Revision 1.43 2003/02/07 10:27:47 billhorsman
1251 change in shutdown procedure to allow re-registration
1252
1253 Revision 1.42 2003/02/07 01:48:15 chr32
1254 Started using new composite listeners.
1255
1256 Revision 1.41 2003/02/06 17:41:04 billhorsman
1257 now uses imported logging
1258
1259 Revision 1.40 2003/02/04 17:18:30 billhorsman
1260 move ShutdownHook init code
1261
1262 Revision 1.39 2003/02/04 15:59:50 billhorsman
1263 finalize now shuts down StatsRoller timer
1264
1265 Revision 1.38 2003/02/02 23:35:48 billhorsman
1266 removed ReloadMonitor to remove use of System properties
1267
1268 Revision 1.37 2003/01/31 16:53:16 billhorsman
1269 checkstyle
1270
1271 Revision 1.36 2003/01/31 11:49:28 billhorsman
1272 use Admin instead of Stats
1273
1274 Revision 1.35 2003/01/31 00:20:05 billhorsman
1275 statistics is now a string to allow multiple,
1276 comma-delimited values (plus better logging of errors
1277 during destruction)
1278
1279 Revision 1.34 2003/01/30 17:22:21 billhorsman
1280 add statistics support
1281
1282 Revision 1.33 2003/01/27 18:26:35 billhorsman
1283 refactoring of ProxyConnection and ProxyStatement to
1284 make it easier to write JDK 1.2 patch
1285
1286 Revision 1.32 2003/01/15 14:51:40 billhorsman
1287 checkstyle
1288
1289 Revision 1.31 2003/01/15 12:01:37 billhorsman
1290 added getDateStarted()
1291
1292 Revision 1.30 2003/01/15 00:07:43 billhorsman
1293 now uses FastArrayList instead of Vector for thread safe
1294 improvements
1295
1296 Revision 1.29 2002/12/18 12:16:22 billhorsman
1297 double checking of connection state counts
1298
1299 Revision 1.28 2002/12/17 17:15:39 billhorsman
1300 Better synchronization of status stuff
1301
1302 Revision 1.27 2002/12/17 16:52:51 billhorsman
1303 synchronize part of removeProxyConnection to avoid
1304 possible bug where connection by status count drifts.
1305
1306 Revision 1.26 2002/12/12 12:28:34 billhorsman
1307 just in case: changed == 0 to < 1
1308
1309 Revision 1.25 2002/12/12 10:48:47 billhorsman
1310 checkstyle
1311
1312 Revision 1.24 2002/12/03 12:24:00 billhorsman
1313 fixed fatal sql exception
1314
1315 Revision 1.23 2002/11/12 20:24:12 billhorsman
1316 checkstyle
1317
1318 Revision 1.22 2002/11/12 20:18:23 billhorsman
1319 Made connection resetter a bit more friendly. Now, if it encounters any problems during
1320 reset then that connection is thrown away. This is going to cause you problems if you
1321 always close connections in an unstable state (e.g. with transactions open. But then
1322 again, it's better to know about that as soon as possible, right?
1323
1324 Revision 1.21 2002/11/09 15:48:55 billhorsman
1325 new isConnectionListenedTo() to stop unnecessary processing
1326 if nobody is listening
1327
1328 Revision 1.20 2002/11/08 18:03:50 billhorsman
1329 when connections are closed because they have been
1330 active for too long then a log message is written
1331 of level WARN, and it includes the name of the
1332 thread responsible (reminder, name your threads).
1333
1334 Revision 1.19 2002/11/07 19:31:25 billhorsman
1335 added sanity check against suspected situation where you
1336 can make more connections than the maximumConnectionCount
1337
1338 Revision 1.18 2002/11/07 19:17:55 billhorsman
1339 removed obsolete method
1340
1341 Revision 1.17 2002/11/06 20:27:30 billhorsman
1342 supports the ConnectionResetter
1343
1344 Revision 1.16 2002/11/05 21:24:18 billhorsman
1345 cosmetic: changed format of statistics dumped to log to make it less confusing for locales that use a space separator for thousands
1346
1347 Revision 1.15 2002/11/02 13:57:33 billhorsman
1348 checkstyle
1349
1350 Revision 1.14 2002/10/30 21:19:17 billhorsman
1351 make use of ProxyFactory
1352
1353 Revision 1.13 2002/10/29 23:00:33 billhorsman
1354 fixed sign error in prototyper (that meant that protoyping never happened)
1355
1356 Revision 1.12 2002/10/29 22:58:22 billhorsman
1357 added connection hashcode to debug
1358
1359 Revision 1.11 2002/10/28 19:44:03 billhorsman
1360 small change to cleanup log
1361
1362 Revision 1.10 2002/10/27 13:02:45 billhorsman
1363 change to prototyper logic to make it clearer (but no functional change)
1364
1365 Revision 1.9 2002/10/27 12:07:45 billhorsman
1366 fix bug where prototyper kept making connections up to maximum. Log now gives reason why connection was prototyped. Fix bug where definition with no properties was not allowed (it is now).
1367
1368 Revision 1.8 2002/10/25 10:12:52 billhorsman
1369 Improvements and fixes to the way connection pools close down. Including new ReloadMonitor to detect when a class is reloaded. Much better logging too.
1370
1371 Revision 1.7 2002/10/24 17:25:20 billhorsman
1372 cleaned up logging and made it more informative
1373
1374 Revision 1.6 2002/10/23 21:04:36 billhorsman
1375 checkstyle fixes (reduced max line width and lenient naming convention
1376
1377 Revision 1.5 2002/10/16 11:46:23 billhorsman
1378 removed obsolete cleanupClob method and made onBirth call failsafe
1379
1380 Revision 1.4 2002/09/19 10:33:57 billhorsman
1381 added ProxyConnection#toString
1382
1383 Revision 1.3 2002/09/18 13:48:56 billhorsman
1384 checkstyle and doc
1385
1386 Revision 1.2 2002/09/13 12:13:50 billhorsman
1387 added debug and fixed ClassCastException during housekeeping
1388
1389 Revision 1.1.1.1 2002/09/13 08:12:55 billhorsman
1390 new
1391
1392 Revision 1.13 2002/08/24 19:57:15 billhorsman
1393 checkstyle changes
1394
1395 Revision 1.12 2002/08/24 19:44:13 billhorsman
1396 fixes for logging
1397
1398 Revision 1.11 2002/07/10 16:14:47 billhorsman
1399 widespread layout changes and move constants into ProxoolConstants
1400
1401 Revision 1.10 2002/07/04 09:05:36 billhorsmaNn
1402 Fixes
1403
1404 Revision 1.9 2002/07/02 11:19:08 billhorsman
1405 layout code and imports
1406
1407 Revision 1.8 2002/07/02 11:14:26 billhorsman
1408 added test (andbug fixes) for FileLogger
1409
1410 Revision 1.7 2002/07/02 08:39:55 billhorsman
1411 getConnectionInfos now returns a Collection instead of an array. displayStatistics is
1412 now available to ProxoolFacade. Prototyper no longer tries to make connections
1413 when maximum is reached (stopping unnecessary log messages). bug fix.
1414
1415 Revision 1.6 2002/06/28 11:19:47 billhorsman
1416 improved doc
1417
1418*/

1419
Popular Tags