Source Code Cross Referenced for Pool.java in  » Database-JDBC-Connection-Pool » Primrose » uk » org » primrose » pool » core » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database JDBC Connection Pool » Primrose » uk.org.primrose.pool.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /**
002:         *	Library name : Primrose - A Java Database Connection Pool.
003:         *	Published by Ben Keeping, http://primrose.org.uk .
004:         *	Copyright (C) 2004 Ben Keeping, primrose.org.uk
005:         *	Email: Use "Contact Us Form" on website
006:         *
007:         *	This library is free software; you can redistribute it and/or
008:         *	modify it under the terms of the GNU Lesser General Public
009:         *	License as published by the Free Software Foundation; either
010:         *	version 2.1 of the License, or (at your option) any later version.
011:         *
012:         *	This library is distributed in the hope that it will be useful,
013:         *	but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *	Lesser General Public License for more details.
016:         *
017:         *	You should have received a copy of the GNU Lesser General Public
018:         *	License along with this library; if not, write to the Free Software
019:         *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
020:         */package uk.org.primrose.pool.core;
021:
022:        import uk.org.primrose.DebugLogger;
023:        import uk.org.primrose.Logger;
024:        import uk.org.primrose.Constants;
025:        import uk.org.primrose.Util;
026:        import uk.org.primrose.pool.*;
027:        import java.sql.*;
028:        import java.util.*;
029:        import uk.org.primrose.pool.core.loadrules.*;
030:
031:        public class Pool extends PoolData {
032:            /**
033:             *	CTOR - init some stuff
034:             */
035:            public Pool() {
036:                lock = new PoolLock();
037:                DebugLogger.log("[Pool:" + this 
038:                        + " ... Creating new lock object : " + lock);
039:            }
040:
041:            /**
042:             *	Get a pooled connection.
043:             *	If the db is down, or all connections in the pool are busy,
044:             *	then wait until we can find a connection ...
045:             * 	unless 1) queueConnectionRequests is false,
046:             *	or     2) waitForConnectionIfDatabaseIsDown is false
047:             * 	whereupon we error, and the client will see a SQLException from
048:             *	the data source object linked to this pool
049:
050:             */
051:            public final Connection getConnection() throws PoolException {
052:                long lid = ++gid;
053:
054:                if (DebugLogger.getEnabled())
055:                    DebugLogger.log("[Pool@" + poolName + ",id=" + lid
056:                            + "] getConnection() start");
057:                // If we are not running in pooled more, then
058:                // just give them a dedicated connection
059:                if (!bRunPooledMode)
060:                    return getNonPooledConnection(lid);
061:
062:                // If all connections are busy, then this throws PoolIsFulLException
063:                // if the pool is configured so that it does not queue connection requests
064:                Connection c = null;
065:
066:                // If we want to wait for a connection if the db is down
067:                // then hide the CannotConnectException
068:                // Else try and get a connection, and throw CannotConnectException (from the internalGetConnection() method)
069:                // if we cannot get one ...
070:
071:                try {
072:                    c = internalGetConnection(lid);
073:                } catch (CannotConnectException cce) {
074:                    if (DebugLogger.getEnabled())
075:                        DebugLogger.log("[Pool@" + poolName + ",id=" + lid
076:                                + "] getConnection() Got exception("
077:                                + cce.getClass().getName()
078:                                + ") getting connection ...");
079:                    // Only throw an exception if we don't want to wait
080:                    // and there is no failoverPool
081:                    if (!bWaitForConnectionIfDatabaseIsDown
082:                            && failoverPool == null) {
083:                        throw cce;
084:                    }
085:
086:                    if (failoverPool != null) {
087:                        notifyExceptionEvent();
088:                    }
089:                }
090:
091:                // Got a connection - return it
092:                if (c != null) {
093:                    if (DebugLogger.getEnabled())
094:                        DebugLogger.log("[Pool@" + poolName + ",id=" + lid
095:                                + "] getConnection() got conn OK - returning");
096:                    return c;
097:                }
098:
099:                // If we get here, then it means that either the db is down
100:                // and we want to wait until it is up,
101:                // or the pool is full, and we want to wait till its not
102:                if (DebugLogger.getEnabled())
103:                    DebugLogger.log("[Pool@" + poolName + ",id=" + lid
104:                            + "] no connection available - waitingThreads("
105:                            + (numberOfWaitingThreads + 1) + ")");
106:                numberOfWaitingThreads++;
107:                return getConnectionWait(lid);
108:            }
109:
110:            /**
111:             *	Can't find a connection - loop until we can ...
112:             * 	unless 1) queueConnectionRequests is false,
113:             *	or     2) waitForConnectionIfDatabaseIsDown is false
114:             * 	whereupon we error, and the client will see a SQLException from
115:             *	the data source object linked to this pool
116:             */
117:            private final Connection getConnectionWait(long id)
118:                    throws PoolException {
119:                if (DebugLogger.getEnabled())
120:                    DebugLogger.log("[Pool@" + poolName + ",id=" + id
121:                            + "] getConnectionWait() start");
122:                try {
123:                    Thread.sleep(250);
124:                } catch (InterruptedException e) {
125:                }
126:
127:                if (DebugLogger.getEnabled())
128:                    DebugLogger.log("[Pool@" + poolName + ",id=" + id
129:                            + "] After 250ms sleep, try to get connection ...");
130:                Connection c = null;
131:                try {
132:                    c = internalGetConnection(id);
133:                } catch (CannotConnectException cce) {
134:                    if (DebugLogger.getEnabled())
135:                        DebugLogger.log("[Pool@" + poolName + ",id=" + id
136:                                + "] getConnectionWait() Got exception("
137:                                + cce.getClass().getName()
138:                                + ") getting connection ...");
139:                    // Only throw an exception if we don't want to wait
140:                    // and there is no failoverPool
141:                    if (!bWaitForConnectionIfDatabaseIsDown
142:                            && failoverPoolObj != null) {
143:                        throw cce;
144:                    }
145:
146:                    if (failoverPoolObj == null && failoverPool != null) {
147:                        notifyExceptionEvent();
148:                    }
149:                }
150:
151:                // Still cannot find a connection ... loop again
152:                if (c == null) {
153:                    int numberOfActiveConnections = numberOfActiveConnections();
154:                    logger
155:                            .verbose("[Pool@"
156:                                    + poolName
157:                                    + ",id="
158:                                    + id
159:                                    + "] getConnectionWait() Could not find a connection ("
160:                                    + numberOfActiveConnections
161:                                    + " active) - sleeping, and trying again");
162:                    return getConnectionWait(id);
163:                }
164:
165:                // yay got one ... decrement the number of waiting threads and return the connection
166:                numberOfWaitingThreads--;
167:                if (DebugLogger.getEnabled())
168:                    DebugLogger
169:                            .log("[Pool@"
170:                                    + poolName
171:                                    + ",id="
172:                                    + id
173:                                    + "] getConnectionWait() got connection now, returning; numberOfWaitingThreads : "
174:                                    + numberOfWaitingThreads);
175:                return c;
176:            }
177:
178:            /**
179:             * 	Initialize a ConnectionHolder for when handing out a new pooled connection
180:             */
181:            private final void initializeConnection(ConnectionHolder ch, long id) {
182:                ch.numberOfOpens++;
183:                try {
184:                    throw new Exception();
185:                } catch (Exception e) {
186:                    ch.callStack = e.getStackTrace();
187:                }
188:
189:                ch.connOpenedDate = System.currentTimeMillis();
190:                ch.status = CONNECTION_ACTIVE;
191:                ch.id = id;
192:                ch.resultsetObjects = new Stack<PoolResultSet>();
193:                ch.statementObjects = new Stack<PoolStatement>();
194:            }
195:
196:            /**
197:             *	Internal get Connection method
198:             * 	Throws PoolHasNoFreeConnections IFF there are no free connections and queueConnectionRequests == false.
199:             *	Throws CannotConnectException if the pool is not full, but we cannot get a connection, or
200:             *	an inactive connection is invalid, and we cannot get a new connection to replace it
201:             */
202:            private final Connection internalGetConnection(long id)
203:                    throws PoolException {
204:                logger.verbose("[Pool@" + poolName + ",id=" + id
205:                        + "] internalGetConnection() called ...");
206:
207:                if (poolAccessLocked) {
208:                    logger.warn("[Pool@" + poolName + ",id=" + id
209:                            + "] getConnection() Pool access is locked ...");
210:                    throw new PoolException("Access to the pool@" + poolName
211:                            + " is locked");
212:                }
213:
214:                // Have we failed over ?
215:                if (failoverPoolObj != null) {
216:                    return failoverPoolObj.internalGetConnection(id);
217:                }
218:
219:                ConnectionHolder retCH = null;
220:
221:                // We want to synchonize access to the core connection list
222:                if (DebugLogger.getEnabled())
223:                    DebugLogger.log("[Pool@" + poolName + ",id=" + id
224:                            + "] intGetConn() About to synch on lock");
225:                synchronized (lock) {
226:                    long now = System.currentTimeMillis();
227:
228:                    // Loop the connections, and try to find an inactive connection
229:                    if (DebugLogger.getEnabled())
230:                        DebugLogger
231:                                .log("[Pool@"
232:                                        + poolName
233:                                        + ",id="
234:                                        + id
235:                                        + "] intGetConn() About to loop connections, size : "
236:                                        + connections.size());
237:                    for (ConnectionHolder ch : connections) {
238:                        if (DebugLogger.getEnabled())
239:                            DebugLogger.log("[Pool@" + poolName + ",id=" + id
240:                                    + "] intGetConn() Connection : "
241:                                    + ch.toString());
242:                        if (ch.status == CONNECTION_INACTIVE) {
243:                            // Initialize the holder and connection
244:                            initializeConnection(ch, id);
245:                            retCH = ch;
246:
247:                            // Cycle connections past their configured number of calls
248:                            // Dump it and go back for another
249:                            if (iCycleConnections > -1) {
250:                                if (ch.numberOfOpens == iCycleConnections) {
251:                                    logger
252:                                            .info("[Pool@"
253:                                                    + poolName
254:                                                    + ",id="
255:                                                    + id
256:                                                    + "] getConnection() Dumping "
257:                                                    + ch.conn
258:                                                    + " because it has executed its max number of calls ("
259:                                                    + iCycleConnections + ")");
260:                                    try {
261:                                        ch.conn.closePhysical();
262:                                    } catch (SQLException sqle) {
263:                                        logger.printStackTrace(sqle);
264:                                    }
265:                                    connections.remove(ch);
266:
267:                                    return internalGetConnection(id);
268:                                }
269:                            }
270:
271:                            // Reset connection defaults
272:                            // If this errors, then the connection will be closed,
273:                            // and removed from the global connections list
274:                            setConnectionDefaults(ch, id);
275:
276:                            logger.verbose("[Pool@" + poolName + ",id=" + id
277:                                    + "] getConnection() using id "
278:                                    + ch.conn.hashCode() + ", "
279:                                    + numberOfActiveConnections()
280:                                    + " in use, caller : " + getCallerString());
281:
282:                            // found one ... break
283:                            totalConnectionsHandedOut++;
284:                            break;
285:                        }
286:                    }
287:
288:                    // No connections in pool, or all active ... try and load a new one
289:                    if (retCH == null) {
290:                        int numberOfLoadedConnections = connections.size();
291:                        // Load a connection if necessary, and if we can (ie active is less than base)
292:                        // Pool is not busy, and there is room to load a new connection
293:                        if (numberOfLoadedConnections < iBase) {
294:
295:                            logger
296:                                    .verbose("[Pool@"
297:                                            + poolName
298:                                            + ",id="
299:                                            + id
300:                                            + "] getConnection() - No loaded connections in pool ... loaded("
301:                                            + numberOfLoadedConnections
302:                                            + ") of base(" + iBase + ")");
303:
304:                            logger
305:                                    .verbose("[Pool@"
306:                                            + poolName
307:                                            + ",id="
308:                                            + id
309:                                            + "] getConnection() loading new connection ...");
310:                            // Load a new connection
311:                            ConnectionHolder ch = loadConnection(false, id);
312:                            // Initialize the holder and connection
313:                            initializeConnection(ch, id);
314:                            // Add it into the pool (marked as ACTIVE)
315:                            connections.addElement(ch);
316:                            // Increment the number of connections handed out
317:                            totalConnectionsHandedOut++;
318:                            retCH = ch;
319:                        } else if (numberOfLoadedConnections == iBase) {
320:                            logger
321:                                    .verbose("[Pool@"
322:                                            + poolName
323:                                            + ",id="
324:                                            + id
325:                                            + "] getConnection() - All loaded conn's in use... loaded("
326:                                            + numberOfLoadedConnections
327:                                            + ") of base(" + iBase + ")");
328:
329:                            StringBuffer stack = new StringBuffer();
330:                            try {
331:                                throw new Exception();
332:                            } catch (Exception e) {
333:                                StackTraceElement[] els = e.getStackTrace();
334:                                for (StackTraceElement el : els) {
335:                                    stack.append("\t");
336:                                    stack.append(el.toString());
337:                                    stack.append("\n");
338:                                }
339:
340:                            }
341:
342:                            logger.email(Constants.NO_FREE_CONNECTIONS_EVENT,
343:                                    "Pool has no free connections - in use("
344:                                            + numberOfLoadedConnections
345:                                            + "), base(" + iBase + ") : "
346:                                            + new java.util.Date() + "\n"
347:                                            + stack.toString());
348:
349:                            // They don't want to wait for a connection, but
350:                            // wish to see an error populated through to the client
351:                            // if there are no connections available
352:                            if (!bQueueConnectionRequests) {
353:                                throw new PoolHasNoFreeConnections();
354:                            }
355:
356:                        }
357:
358:                        // Loaded conn OK ... recurse to pick up
359:                        //return internalGetConnection();
360:                    }
361:
362:                    logger.verbose("[Pool@" + poolName + ",id=" + id
363:                            + "] getConnection() took "
364:                            + (System.currentTimeMillis() - now) + "ms");
365:                } // end synch block
366:
367:                if (retCH == null)
368:                    return null;
369:
370:                // Check if the connection is OK
371:                // If it is not, dump it, and load another, and then recurse back
372:                // If it looks like the db is down, then depending on the value
373:                // of waitForConnectionIfDatabaseIsDown, then either throw an exception
374:                // or recurse
375:                boolean conOK = checkIfConnectionIsValid(retCH.conn, id);
376:
377:                if (!conOK) {
378:                    logger.verbose("[Pool@" + poolName + ",id=" + id
379:                            + "] getConnection() Dumping " + retCH.conn
380:                            + " because it failed validity checks.");
381:                    try {
382:                        retCH.conn.closePhysical();
383:                    } catch (SQLException sqle) {
384:                        logger.printStackTrace(sqle);
385:                    }
386:                    connections.remove(retCH);
387:
388:                    this .notifyExceptionEvent();
389:                    try {
390:                        Thread.sleep(250);
391:                    } catch (InterruptedException ie) {
392:                    }
393:                    return internalGetConnection(id);
394:                }
395:
396:                return retCH.conn;
397:            }
398:
399:            /**
400:             * Get who called the getConnection() method
401:             * @return String
402:             */
403:            private String getCallerString() {
404:                try {
405:                    throw new Exception();
406:                } catch (Exception e) {
407:                    int maxBacktraceCount = 5;
408:                    StackTraceElement[] ste = e.getStackTrace();
409:                    StringBuffer caller = new StringBuffer(100);
410:                    boolean start = false;
411:                    for (int i = 0; i < ste.length; i++) {
412:                        if (ste[i].getClassName()
413:                                .endsWith("PrimroseDataSource")) {
414:                            start = true;
415:                            continue;
416:                        }
417:
418:                        if (start && maxBacktraceCount > 0) {
419:                            maxBacktraceCount--;
420:                            if (maxBacktraceCount == 0) {
421:                                caller.append(ste[i].getFileName() + "[method:"
422:                                        + ste[i].getMethodName() + ",line:"
423:                                        + ste[i].getLineNumber() + "]");
424:                            } else {
425:                                caller.append(ste[i].getFileName() + "[method:"
426:                                        + ste[i].getMethodName() + ",line:"
427:                                        + ste[i].getLineNumber() + "], ");
428:                            }
429:                        }
430:                    }
431:                    return caller.toString();
432:                }
433:
434:            }
435:
436:            /**
437:             *	Apply default connection properties to the connection
438:             *	Called from fill() when a brand new connection is added to the pool,
439:             *	and from put() when a connection is returned to the pool
440:             *	If the check methods fail (SQLException), the underlying connection will be closed down,
441:             *	and removed from the pool list
442:             */
443:            protected final void setConnectionDefaults(ConnectionHolder ch,
444:                    long id) throws PoolException {
445:                if (DebugLogger.getEnabled())
446:                    DebugLogger.log("[Pool@" + poolName + ",id=" + id
447:                            + "] setConnectionDefaults() start");
448:                Connection c = ch.conn;
449:                // set the default auto commit value
450:                try {
451:                    if (c.getAutoCommit() != bConnectionAutoCommit) {
452:                        // don't log changes to driver defaults if the connection
453:                        // is brand new
454:                        if (ch.numberOfOpens > 0) {
455:                            logger
456:                                    .warn("[Pool@"
457:                                            + poolName
458:                                            + ",id="
459:                                            + id
460:                                            + "] setConnectionDefaults() : Checking autocommit value : Looks like someone has changed it from the default, and has not set it back. Default should be '"
461:                                            + bConnectionAutoCommit
462:                                            + "', but the connection value is '"
463:                                            + c.getAutoCommit() + "'");
464:                        }
465:                        c.setAutoCommit(bConnectionAutoCommit);
466:
467:                    }
468:                } catch (SQLException sqle) {
469:                    logger.printStackTrace(sqle);
470:                    ch.closeBehaviour = Pool.ON_CLOSE_SHOULD_DIE;
471:                    ch.conn.close();
472:                    connections.remove(ch);
473:                    logger
474:                            .warn("[Pool@"
475:                                    + poolName
476:                                    + ",id="
477:                                    + id
478:                                    + "] setConnectionDefaults() : Error checking auto commit. Connection will be dumped.");
479:                    notifyExceptionEvent();
480:                    throw new CannotConnectException(
481:                            "Checking auto commit value errored : "
482:                                    + sqle.toString(), sqle);
483:                }
484:
485:                // set the default transaction isolation level
486:                // if the user has specified they want it in primrose.config.
487:                // Else, just leave it as the default
488:                if (iConnectionTransactionIsolation != -1) {
489:                    try {
490:                        // if it is -1, then set the default
491:                        //if (iConnectionTransactionIsolation == -1) {
492:                        //	setInternalConnectionTransactionIsolation(null);
493:                        //}
494:                        // if the connections setting does not equal the pool's,
495:                        // then set it (and log that somone changed it, but did not set it back
496:                        if (c.getTransactionIsolation() != iConnectionTransactionIsolation) {
497:                            // don't log changes to driver defaults if the connection
498:                            // is brand new
499:                            if (ch.numberOfOpens > 0) {
500:                                logger
501:                                        .warn("[Pool@"
502:                                                + poolName
503:                                                + ",id="
504:                                                + id
505:                                                + "] setConnectionDefaults() : Checking transaction isolation level : Looks like someone has changed it from the default, and has not set it back. Default should be '"
506:                                                + getInternalConnectionTransactionIsolation()
507:                                                + "', but the connection value is '"
508:                                                + getInternalConnectionTransactionIsolation(c
509:                                                        .getTransactionIsolation())
510:                                                + "'");
511:                            }
512:                            c
513:                                    .setTransactionIsolation(iConnectionTransactionIsolation);
514:                        }
515:                    } catch (SQLException sqle) {
516:                        logger.printStackTrace(sqle);
517:                        ch.closeBehaviour = Pool.ON_CLOSE_SHOULD_DIE;
518:                        ch.conn.close();
519:                        connections.remove(ch);
520:                        logger
521:                                .warn("[Pool@"
522:                                        + poolName
523:                                        + ",id="
524:                                        + id
525:                                        + "] setConnectionDefaults() : Error checking transaction isolation level. Connection will be dumped.");
526:                        notifyExceptionEvent();
527:                        throw new CannotConnectException(
528:                                "Checking transaction isolation level value errored : "
529:                                        + sqle.toString(), sqle);
530:                    }
531:                }
532:
533:                if (DebugLogger.getEnabled())
534:                    DebugLogger.log("[Pool@" + poolName + ",id=" + id
535:                            + "] setConnectionDefaults() leave");
536:            }
537:
538:            /**
539:             *	Check if a connection is valid. This calls isClosed() (once we go to Java 6, we can call isValid())
540:             *	If user has configured "checkSQL" option, we run that also.
541:             *	If either checks fail, the connection is dumped.
542:             */
543:            private final boolean checkIfConnectionIsValid(Connection c, long id) {
544:                if (DebugLogger.getEnabled())
545:                    DebugLogger.log("[Pool@" + poolName + ",id=" + id
546:                            + "] checkIfConnectionIsValid() start");
547:
548:                long now = System.currentTimeMillis();
549:
550:                boolean checkret = false;
551:
552:                try {
553:                    checkret = c.isClosed();
554:                    checkret = true;
555:                } catch (SQLException e) {
556:                    logger
557:                            .error("[Pool@"
558:                                    + poolName
559:                                    + ",id="
560:                                    + id
561:                                    + "] checkIfConnectionIsValid() : Error calling isClosed() on connection "
562:                                    + c + " : " + e);
563:                }
564:
565:                // If its false (ie isClosed() returned false, then return false
566:                if (!checkret)
567:                    return false;
568:
569:                // Only run a check if they want it
570:                if (checkSQL != null && checkSQL.length() > 0) {
571:                    logger
572:                            .verbose("[Pool@"
573:                                    + poolName
574:                                    + ",id="
575:                                    + id
576:                                    + "] checkIfConnectionIsValid() : running checkSQL : "
577:                                    + checkSQL);
578:                    checkret = ((PoolConnection) c).runCheckSQL(checkSQL);
579:
580:                }
581:                logger.verbose("[Pool@" + poolName + ",id=" + id
582:                        + "] checkIfConnectionIsValid(" + checkret
583:                        + ") : took " + (System.currentTimeMillis() - now)
584:                        + " ms");
585:
586:                return checkret;
587:            }
588:
589:            /**
590:             * Get a non pooled connection - ie just a dedicated connection
591:             * that someone can use once and once only.
592:             * So when the client calls close(), the connection dies off
593:             * @return a Connection object
594:             */
595:            private final Connection getNonPooledConnection(long id)
596:                    throws PoolException {
597:                if (DebugLogger.getEnabled())
598:                    DebugLogger.log("[Pool@" + poolName + ",id=" + id
599:                            + "] getNonPooledConnection() start");
600:
601:                ConnectionHolder ch = loadConnection(false, id);
602:                initializeConnection(ch, id);
603:                // override the close behaviour because its a non-pooled connection
604:                ch.closeBehaviour = ON_CLOSE_SHOULD_DIE;
605:
606:                if (DebugLogger.getEnabled())
607:                    DebugLogger.log("[Pool@" + poolName + ",id=" + id
608:                            + "] getNonPooledConnection() end : " + ch.conn);
609:                return ch.conn;
610:            }
611:
612:            /**
613:             * Get a ConnectionHolder object, with the connection in it.
614:             *
615:             * @param addToList - should the ConnectionHolder be added to the list
616:             * of pooled connections
617:             * @return a ConnectionHolder object which contains the connection
618:             * @throws PoolException
619:             */
620:            private final ConnectionHolder loadConnection(boolean addToList,
621:                    long id) throws PoolException {
622:                if (DebugLogger.getEnabled())
623:                    DebugLogger.log("[Pool@" + poolName + ",id=" + id
624:                            + "] loadConnection() start");
625:                Connection raw = Util.getConnection(driverClass, driverURL,
626:                        user, password);
627:                ConnectionHolder ch = new ConnectionHolder();
628:                PoolConnection pc = new PoolConnection(raw, ch);
629:                ch.conn = pc;
630:                ch.closeBehaviour = ON_CLOSE_SHOULD_REUSE;
631:                ch.status = CONNECTION_INACTIVE;
632:                ch.lock = lock;
633:                ch.poolName = poolName;
634:                ch.bDumpConnectionOnSQLException = this .bDumpConnectionOnSQLException;
635:                ch.myPool = this ;
636:                ch.logger = this .logger;
637:
638:                setConnectionDefaults(ch, id);
639:
640:                if (addToList) {
641:                    connections.addElement(ch);
642:                }
643:                return ch;
644:            }
645:
646:            /**
647:             *	Close down all connection objects, and remove them from the connection list
648:             *	If force is true, then close the connection down immediately, else
649:             * 	leave them to finish their job, and then close them. This means that pools can
650:             *	be stopped/started with no impact on live connections (ie safely).
651:             */
652:            public final void stop(boolean force) throws PoolException {
653:                if (bPoolHasBeenShutdown) {
654:                    logger
655:                            .warn("[Pool@"
656:                                    + poolName
657:                                    + "] stop() Pool has already been shutdown ... not doing it twice.");
658:                    return;
659:                }
660:                logger.email(Constants.STOP_EVENT, "Pool stopping at : "
661:                        + new java.util.Date());
662:
663:                logger
664:                        .info("[Pool@" + poolName
665:                                + "] stop() Stopping pool with force=" + force
666:                                + " ...");
667:                // Lock access to the pool
668:                poolAccessLocked = true;
669:
670:                // Kill the cutback failover thread if it exists
671:                if (failoverCutBackObj != null) {
672:                    failoverCutBackObj.stopIt();
673:                }
674:
675:                // Close down each connection
676:                for (ConnectionHolder ch : connections) {
677:                    // If we are forcing a close, just dump it
678:                    // Else, only dump if not busy
679:                    // If they are busy, and we are not forcing close, then mark the connection
680:                    // as not returning to the pool once its free (ie dump after work is done)
681:                    try {
682:                        if (force) {
683:                            ch.conn.closePhysical();
684:                        } else {
685:                            if (ch.status == CONNECTION_INACTIVE) {
686:                                ch.conn.closePhysical();
687:                            } else {
688:                                ch.closeBehaviour = ON_CLOSE_SHOULD_DIE;
689:                            }
690:                        }
691:                    } catch (SQLException e) {
692:                        logger.printStackTrace(e);
693:                    }
694:                }
695:
696:                connections.removeAllElements();
697:
698:                logger.info("[Pool@" + poolName
699:                        + "] stop() Shutting down pool monitor.");
700:                if (monitor != null) {
701:                    monitor.shutdown();
702:                }
703:
704:                logger.info("[Pool@" + poolName + "] stop() Stop Complete.");
705:                logger.close();
706:                bPoolHasBeenShutdown = true;
707:            }
708:
709:            /**
710:             *	Start the pool, filling it with the configured base of connections
711:             */
712:            public final void start() throws PoolException {
713:                // set up the logger
714:                setUpLogger();
715:                gid = 0L;
716:                bPoolHasBeenShutdown = false;
717:
718:                logger.verbose("[Pool@" + poolName + "] Checking " + poolName
719:                        + " parameters ...");
720:
721:                for (LoadRule rule : loadRules) {
722:                    rule.runCheck(this , this .logger);
723:                }
724:
725:                logger.email(Constants.START_EVENT, "Pool starting at : "
726:                        + new java.util.Date());
727:
728:                // print some verbose logging
729:                logger.info("[Pool@" + poolName + "] STARTING " + poolName
730:                        + " ...");
731:                Util.printGetMethodValues("[Pool@" + poolName
732:                        + "] config item : ", logger, PoolConfigImpl.class,
733:                        this );
734:
735:                // Lock access to the pool
736:                poolAccessLocked = true;
737:
738:                // Make a new list
739:                connections = new Vector<ConnectionHolder>();
740:                numberOfWaitingThreads = 0;
741:                totalConnectionsHandedOut = 0;
742:                if (iNumberOfConnectionsToInitializeWith > iBase) {
743:                    logger
744:                            .warn("[Pool@"
745:                                    + poolName
746:                                    + "] start() The number of connections to initialise with is greater than the number of base connections ... adjusting init number to base : "
747:                                    + iBase);
748:                    iNumberOfConnectionsToInitializeWith = iBase;
749:                }
750:                logger.verbose("[Pool@" + poolName + "] start() Loading "
751:                        + iNumberOfConnectionsToInitializeWith
752:                        + " Connection(s) on init");
753:
754:                for (int i = 0; i < iNumberOfConnectionsToInitializeWith; i++) {
755:                    try {
756:                        Connection pc = loadConnection(true, i).conn;
757:                        if (i == 0) {
758:                            DatabaseMetaData conMD = pc.getMetaData();
759:                            logger.info("[Pool@" + poolName
760:                                    + "] start() Primrose version "
761:                                    + Constants.VERSION + ", release date "
762:                                    + Constants.RELEASE_DATE);
763:                            logger.info("[Pool@" + poolName
764:                                    + "] start() JDBC Driver Name: "
765:                                    + conMD.getDriverName());
766:                            logger.info("[Pool@" + poolName
767:                                    + "] start() JDBC Driver Version: "
768:                                    + conMD.getDriverVersion());
769:                        }
770:                    } catch (Throwable t) {
771:                        logger
772:                                .warn("[Pool@"
773:                                        + poolName
774:                                        + "] start() Could not connect to db - is this OK ?");
775:                        logger.printStackTrace(t);
776:                    }
777:                }
778:
779:                logger.info("[Pool@" + poolName
780:                        + "] start() Starting new pool monitor.");
781:                monitor = new PoolMonitor(this , logger);
782:                monitor.start();
783:
784:                logger.info("[Pool@" + poolName + "] start() Load complete.");
785:
786:                // Unlock access to the pool - make it available
787:                poolAccessLocked = false;
788:            }
789:
790:            public final Vector<ConnectionHolder> getPoolConnections() {
791:                return connections;
792:            }
793:
794:            /**
795:             *	Restart the pool, calling stop(), then start()
796:             */
797:            public final void restart(boolean forceStop) throws PoolException {
798:                logger.info("[Pool@" + poolName
799:                        + "] restart() Restarting pool ...");
800:                stop(forceStop);
801:                start();
802:                logger.info("[Pool@" + poolName
803:                        + "] restart() Restart Complete ...");
804:            }
805:
806:            public Logger getLogger() {
807:                return logger;
808:            }
809:
810:            /**
811:             * 	If a SQLException occurs and the parameter 'dumpConnectionOnSQLException' is true (default)
812:             *	then this method is called.
813:             *	If the config requires emails to be sent on SQLExceptions, then send it.
814:             *	If we require notification of a possible DB crash, then see if we have, using the
815:             * 	'onExceptionCheckSQL' parameter SQL.
816:             * 	If the config requires failover, then attempt that (if the db has crashed).
817:             */
818:            protected void notifyExceptionEvent() {
819:                if (emailEvents != null) {
820:                    boolean notifyException = emailEvents.toUpperCase()
821:                            .indexOf(Constants.EXCEPTION_EVENT.toUpperCase()) > -1;
822:                    boolean notifyCrash = emailEvents.toUpperCase().indexOf(
823:                            Constants.DBCRASH_EVENT.toUpperCase()) > -1;
824:
825:                    if (notifyException) {
826:                        logger.email(Constants.EXCEPTION_EVENT,
827:                                "SQLException has occured in pool " + poolName);
828:                    }
829:
830:                    if (notifyCrash) {
831:                        boolean bHasCrashed = hasDbCrashed();
832:
833:                        if (notifyCrash && bHasCrashed) {
834:                            logger.email(Constants.DBCRASH_EVENT,
835:                                    "Database seems to have crashed ! Driver URL : "
836:                                            + driverURL);
837:                        }
838:                        // If we don't want failover, or we already have failed over, then ignore
839:                        if (failoverPool != null && failoverPoolObj == null) {
840:                            attemptFailover();
841:                        }
842:                    }
843:                }
844:
845:                // If we want failover, and we habe not already failed over, then
846:                // attempt a failover
847:                if (failoverPool != null && failoverPoolObj == null) {
848:                    boolean bHasCrashed = hasDbCrashed();
849:                    if (bHasCrashed) {
850:                        attemptFailover();
851:                    }
852:                }
853:            }
854:
855:            /*
856:             * Work out if the db has crashed by running
857:             */
858:            private boolean hasDbCrashed() {
859:                boolean bHasCrashed = false;
860:
861:                logger
862:                        .verbose("[Pool@"
863:                                + poolName
864:                                + "] About to see if DB has crashed (get new connection & run onExceptionCheckSQL)...");
865:                try {
866:                    if (DebugLogger.getEnabled())
867:                        DebugLogger.log("[Pool@" + poolName
868:                                + "] hasDbCrashed() Loading connection ...");
869:                    //Throws exception if fails ( == yes, failover)
870:                    ConnectionHolder ch = loadConnection(false, -7777);
871:                    Connection c = ch.conn;
872:                    // false == fail check, true == passed check
873:                    // so bHasCrashed = !checkval
874:                    if (DebugLogger.getEnabled())
875:                        DebugLogger
876:                                .log("[Pool@"
877:                                        + poolName
878:                                        + "] hasDbCrashed() Running onExceptionCheckSQL statement ...");
879:                    bHasCrashed = ((PoolConnection) c)
880:                            .runCheckSQL(onExceptionCheckSQL);
881:                    if (DebugLogger.getEnabled())
882:                        DebugLogger.log("[Pool@" + poolName
883:                                + "] hasDbCrashed() runCheckSQL returned "
884:                                + bHasCrashed);
885:
886:                    bHasCrashed = !bHasCrashed;
887:
888:                    try {
889:                        if (c != null)
890:                            c.close();
891:                    } catch (SQLException sqle) {
892:                    }
893:                } catch (PoolException pe) {
894:                    logger.printStackTrace(pe);
895:                    bHasCrashed = true;
896:                }
897:
898:                if (DebugLogger.getEnabled())
899:                    DebugLogger.log("[Pool@" + poolName + "] hasDbCrashed ? : "
900:                            + bHasCrashed);
901:                return bHasCrashed;
902:            }
903:
904:            /*
905:             * If failoverPool is set, and we have failed over, and then the DB is back up
906:             * then cutback to this pool.
907:             */
908:            public void cutbackFromFailoverPool() {
909:                logger.info("[Pool@" + poolName
910:                        + "] Cutting back to this pool from failoverPool "
911:                        + failoverPool);
912:                logger.email(Constants.CUTBACK_EVENT,
913:                        "Cutting back to this pool from failoverPool "
914:                                + failoverPool);
915:                try {
916:                    stop(false);
917:                    start();
918:                    failoverPoolObj = null;
919:                    logger.info("[Pool@" + poolName
920:                            + "] Cutback to original pool succeeded");
921:                    logger.email(Constants.CUTBACK_EVENT,
922:                            "Cutback to original pool succeeded");
923:                } catch (PoolException pe) {
924:                    logger.error("Cutback failed ...");
925:                    logger.printStackTrace(pe);
926:                    logger.email(Constants.CUTBACK_EVENT, "Cutback failed : "
927:                            + pe);
928:                }
929:            }
930:
931:            /**
932:             * 	If a SQLException occurs and the parameter 'dumpConnectionOnSQLException' is true (default)
933:             * 	and the parameter 'failoverPool' is set, then see if we should failover.
934:             */
935:            private void attemptFailover() {
936:                logger.info("[Pool@" + poolName
937:                        + "] Now attemping failover to pool '" + failoverPool
938:                        + "'");
939:                logger
940:                        .email(Constants.FAILOVER_EVENT,
941:                                "Now attemping failover to pool '"
942:                                        + failoverPool + "'");
943:                try {
944:                    logger.info("[Pool@" + poolName + "] Finding failoverPool("
945:                            + failoverPool + ")");
946:                    // Restart and change the pool name
947:                    failoverPoolObj = PoolLoader.findExistingPool(failoverPool);
948:                    if (failoverPoolObj == null) {
949:                        throw new PoolException("Cannot find failoverPool("
950:                                + failoverPool + ") !");
951:                    }
952:                    logger.info("[Pool@" + poolName
953:                            + "] Stopping this pool ...");
954:                    stop(true);
955:
956:                    poolAccessLocked = false;
957:                    logger
958:                            .info("[Pool@"
959:                                    + poolName
960:                                    + "] Testing that can get connection from failoverPool ...");
961:
962:                    Connection c = getConnection();
963:                    try {
964:                        if (c != null)
965:                            c.close();
966:                    } catch (SQLException sqle) {
967:                    }
968:
969:                    logger.info("[Pool@" + poolName
970:                            + "] Starting failover cutback monitor ...");
971:                    failoverCutBackObj = new FailoverCutBack(this , logger);
972:                    failoverCutBackObj.start();
973:
974:                    logger.info("[Pool@" + poolName
975:                            + "] Failover complete. Routing all requests to "
976:                            + poolName + " to " + failoverPool);
977:                    logger.email(Constants.FAILOVER_EVENT,
978:                            "Failover complete. Routing all requests to "
979:                                    + poolName + " to " + failoverPool);
980:                } catch (PoolException pe) {
981:                    logger.error("[Pool@" + poolName + "] Failover failed : "
982:                            + pe.toString());
983:                    logger.email(Constants.FAILOVER_EVENT, "Failover failed : "
984:                            + pe.toString());
985:                    logger.printStackTrace(pe);
986:                }
987:
988:            }
989:
990:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.