Source Code Cross Referenced for ConnectionResetter.java in  » Database-JDBC-Connection-Pool » proxool » org » logicalcobwebs » proxool » 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 » proxool » org.logicalcobwebs.proxool 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * This software is released under a licence similar to the Apache Software Licence.
003:         * See org.logicalcobwebs.proxool.package.html for details.
004:         * The latest version is available at http://proxool.sourceforge.net
005:         */
006:        package org.logicalcobwebs.proxool;
007:
008:        import org.apache.commons.logging.Log;
009:        import org.apache.commons.logging.Log;
010:
011:        import java.lang.reflect.Method;
012:        import java.sql.Connection;
013:        import java.sql.SQLException;
014:        import java.util.HashMap;
015:        import java.util.HashSet;
016:        import java.util.Iterator;
017:        import java.util.Map;
018:        import java.util.Set;
019:
020:        /**
021:         * Responsible for resetting a Connection to its default state when it is
022:         * returned to the pool. It must be initialised by the first Connection that
023:         * is made (for each pool) so that we don't make any assumptions about
024:         * what the default values are.
025:         *
026:         * @version $Revision: 1.16 $, $Date: 2006/01/18 14:40:01 $
027:         * @author Bill Horsman (bill@logicalcobwebs.co.uk)
028:         * @author $Author: billhorsman $ (current maintainer)
029:         * @since Proxool 0.5
030:         */
031:        public class ConnectionResetter {
032:
033:            private Log log;
034:
035:            /**
036:             * @see #initialise
037:             */
038:            private boolean initialised;
039:
040:            /**
041:             * @see #addReset
042:             * @see #reset
043:             */
044:            private Map accessorMutatorMap = new HashMap();
045:
046:            /**
047:             * @see #addReset
048:             * @see #reset
049:             */
050:            private Map defaultValues = new HashMap();
051:
052:            /**
053:             * We use this to guess if we are changing a property that will need resetting
054:             */
055:            protected static final String MUTATOR_PREFIX = "set";
056:
057:            private String driverName;
058:
059:            /**
060:             * @see #isTriggerResetException() 
061:             */
062:            protected static boolean triggerResetException;
063:
064:            /**
065:             * Pass in the log to use
066:             * @param log debug information sent here
067:             */
068:            protected ConnectionResetter(Log log, String driverName) {
069:                this .log = log;
070:                this .driverName = driverName;
071:
072:                // Map all the reset methods
073:                addReset("getCatalog", "setCatalog");
074:                addReset("isReadOnly", "setReadOnly");
075:                addReset("getTransactionIsolation", "setTransactionIsolation");
076:                addReset("getTypeMap", "setTypeMap");
077:                addReset("getHoldability", "setHoldability");
078:            }
079:
080:            /**
081:             * Add a pair of methods that need resetting each time a connection is
082:             * put back in the pool
083:             * @param accessorName the name of the "getter" method (e.g. getAutoCommit)
084:             * @param mutatorName teh name of the "setter" method (e.g. setAutoCommit)
085:             */
086:            private void addReset(String accessorName, String mutatorName) {
087:
088:                try {
089:
090:                    Method accessor = null;
091:                    Method mutator = null;
092:
093:                    Method[] methods = Connection.class.getMethods();
094:                    for (int i = 0; i < methods.length; i++) {
095:                        Method method = methods[i];
096:                        if (method.getName().equals(accessorName)) {
097:                            if (accessor == null) {
098:                                accessor = method;
099:                            } else {
100:                                log.info("Skipping ambiguous reset method "
101:                                        + accessorName);
102:                                return;
103:                            }
104:                        }
105:                        if (method.getName().equals(mutatorName)) {
106:                            if (mutator == null) {
107:                                mutator = method;
108:                            } else {
109:                                log.info("Skipping ambiguous reset method "
110:                                        + mutatorName);
111:                                return;
112:                            }
113:                        }
114:                    }
115:
116:                    if (accessor == null) {
117:                        log
118:                                .debug("Ignoring attempt to map reset method "
119:                                        + accessorName
120:                                        + " (probably because it isn't implemented in this JDK)");
121:                    } else if (mutator == null) {
122:                        log
123:                                .debug("Ignoring attempt to map reset method "
124:                                        + mutatorName
125:                                        + " (probably because it isn't implemented in this JDK)");
126:                    } else if (accessorMutatorMap.containsKey(accessor)) {
127:                        log
128:                                .warn("Ignoring attempt to map duplicate reset method "
129:                                        + accessorName);
130:                    } else if (accessorMutatorMap.containsValue(mutator)) {
131:                        log
132:                                .warn("Ignoring attempt to map duplicate reset method "
133:                                        + mutatorName);
134:                    } else {
135:
136:                        if (mutatorName.indexOf(MUTATOR_PREFIX) != 0) {
137:                            log
138:                                    .warn("Resetter mutator "
139:                                            + mutatorName
140:                                            + " does not start with "
141:                                            + MUTATOR_PREFIX
142:                                            + " as expected. Proxool maynot recognise that a reset is necessary.");
143:                        }
144:
145:                        if (accessor.getParameterTypes().length > 0) {
146:                            log.info("Ignoring attempt to map accessor method "
147:                                    + accessorName
148:                                    + ". It must have no arguments.");
149:                        } else if (mutator.getParameterTypes().length != 1) {
150:                            log
151:                                    .info("Ignoring attempt to map mutator method "
152:                                            + mutatorName
153:                                            + ". It must have exactly one argument, not "
154:                                            + mutator.getParameterTypes().length);
155:                        } else {
156:                            accessorMutatorMap.put(accessor, mutator);
157:                        }
158:                    }
159:                } catch (Exception e) {
160:                    log.error("Problem mapping " + accessorName + " and "
161:                            + mutatorName, e);
162:                }
163:
164:            }
165:
166:            /**
167:             * This gets called every time we make a Connection. Not that often
168:             * really, so it's ok to synchronize a bit.
169:             * @param connection this will be used to get all the default values
170:             */
171:            protected void initialise(Connection connection) {
172:                if (!initialised) {
173:                    synchronized (this ) {
174:                        if (!initialised) {
175:
176:                            Set accessorsToRemove = new HashSet();
177:                            Iterator i = accessorMutatorMap.keySet().iterator();
178:                            while (i.hasNext()) {
179:                                Method accessor = (Method) i.next();
180:                                Method mutator = (Method) accessorMutatorMap
181:                                        .get(accessor);
182:                                Object value = null;
183:                                try {
184:                                    value = accessor.invoke(connection, null);
185:                                    // It's perfectly ok for the default value to be null, we just
186:                                    // don't want to add it to the map.
187:                                    if (value != null) {
188:                                        defaultValues.put(mutator, value);
189:                                    }
190:                                    if (log.isDebugEnabled()) {
191:                                        log.debug("Remembering default value: "
192:                                                + accessor.getName() + "() = "
193:                                                + value);
194:                                    }
195:
196:                                } catch (Throwable t) {
197:                                    log.debug(driverName + " does not support "
198:                                            + accessor.getName()
199:                                            + ". Proxool doesn't mind.");
200:                                    // We will remove this later (to avoid ConcurrentModifcation)
201:                                    accessorsToRemove.add(accessor);
202:                                }
203:
204:                                // Just test that the mutator works too. Otherwise it's going to fall over
205:                                // everytime we close a connection
206:                                try {
207:                                    Object[] args = { value };
208:                                    mutator.invoke(connection, args);
209:                                } catch (Throwable t) {
210:                                    log.debug(driverName + " does not support "
211:                                            + mutator.getName()
212:                                            + ". Proxool doesn't mind.");
213:                                    // We will remove this later (to avoid ConcurrentModifcation)
214:                                    accessorsToRemove.add(accessor);
215:                                }
216:
217:                            }
218:
219:                            // Remove all the reset methods that we had trouble configuring
220:                            Iterator j = accessorsToRemove.iterator();
221:                            while (j.hasNext()) {
222:                                Method accessor = (Method) j.next();
223:                                Method mutator = (Method) accessorMutatorMap
224:                                        .get(accessor);
225:                                accessorMutatorMap.remove(accessor);
226:                                defaultValues.remove(mutator);
227:                            }
228:
229:                            initialised = true;
230:                        }
231:                    }
232:                }
233:            }
234:
235:            /**
236:             * Reset this connection to its default values. If anything goes wrong, it is logged
237:             * as a warning or info but it silently continues.
238:             * @param connection to be reset
239:             * @param id used in log messages
240:             * @return true if the reset was error free, or false if it encountered errors. (in which case it should probably not be reused)
241:             */
242:            protected boolean reset(Connection connection, String id) {
243:                boolean errorsEncountered = false;
244:
245:                try {
246:                    connection.clearWarnings();
247:                } catch (SQLException e) {
248:                    errorsEncountered = true;
249:                    log.warn(id
250:                            + " - Problem calling connection.clearWarnings()",
251:                            e);
252:                }
253:
254:                // Let's see the state of autoCommit. It will help us give better advice in the log messages
255:                boolean autoCommit = true;
256:                try {
257:                    autoCommit = connection.getAutoCommit();
258:                } catch (SQLException e) {
259:                    errorsEncountered = true;
260:                    log.warn(id
261:                            + " - Problem calling connection.getAutoCommit()",
262:                            e);
263:                }
264:
265:                /*
266:                 Automatically rollback if autocommit is off. If there are no pending
267:                 transactions then this will have no effect.
268:
269:                 From Database Language SQL (Proposed revised text of DIS 9075),
270:                 July 1992 - http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
271:
272:                 "The execution of a <rollback statement> may be initiated implicitly by
273:                 an implementation when it detects unrecoverable errors. When such an
274:                 error occurs, an exception condition is raised: transaction rollback
275:                 with an implementation-defined subclass code".
276:
277:                 */
278:                if (!autoCommit) {
279:                    try {
280:                        connection.rollback();
281:                    } catch (SQLException e) {
282:                        log
283:                                .error(
284:                                        "Unexpected exception whilst calling rollback during connection reset",
285:                                        e);
286:                    }
287:                }
288:
289:                // Now let's reset each property in turn. With a bit of luck, if there is a
290:                // transaction pending then setting one of these properties will throw an
291:                // exception (e.g. "operation not possible when transaction is in progress"
292:                // or something). We want to know about transactions that are pending.
293:                // It doesn't seem like a very good idea to close a connection with
294:                // pending transactions.
295:                Iterator i = accessorMutatorMap.keySet().iterator();
296:                while (i.hasNext()) {
297:                    Method accessor = (Method) i.next();
298:                    Method mutator = (Method) accessorMutatorMap.get(accessor);
299:                    Object[] args = { defaultValues.get(mutator) };
300:                    try {
301:                        Object currentValue = accessor.invoke(connection, null);
302:                        if (currentValue == null && args[0] == null) {
303:                            // Nothing to do then
304:                        } else if (currentValue.equals(args[0])) {
305:                            // Nothing to do here either
306:                        } else {
307:                            mutator.invoke(connection, args);
308:                            if (log.isDebugEnabled()) {
309:                                log.debug(id + " - Reset: " + mutator.getName()
310:                                        + "(" + args[0] + ") from "
311:                                        + currentValue);
312:                            }
313:                        }
314:                    } catch (Throwable t) {
315:                        errorsEncountered = true;
316:                        if (log.isDebugEnabled()) {
317:                            log.debug(id + " - Problem resetting: "
318:                                    + mutator.getName() + "(" + args[0] + ").",
319:                                    t);
320:                        }
321:                    }
322:                }
323:
324:                // Finally. reset autoCommit.
325:                if (!autoCommit) {
326:                    try {
327:                        // Setting autoCommit to true might well commit all pending
328:                        // transactions. But that's beyond our control.
329:                        connection.setAutoCommit(true);
330:                        log.debug(id + " - autoCommit reset back to true");
331:                    } catch (Throwable t) {
332:                        errorsEncountered = true;
333:                        log
334:                                .warn(
335:                                        id
336:                                                + " - Problem calling connection.commit() or connection.setAutoCommit(true)",
337:                                        t);
338:                    }
339:                }
340:
341:                if (isTriggerResetException()) {
342:                    log.warn("Triggering pretend exception during reset");
343:                    errorsEncountered = true;
344:                }
345:
346:                if (errorsEncountered) {
347:
348:                    log
349:                            .warn(id
350:                                    + " - There were some problems resetting the connection (see debug output for details). It will not be used again "
351:                                    + "(just in case). The thread that is responsible is named '"
352:                                    + Thread.currentThread().getName() + "'");
353:                    if (!autoCommit) {
354:                        log
355:                                .warn(id
356:                                        + " - The connection was closed with autoCommit=false. That is fine, but it might indicate that "
357:                                        + "the problems that happened whilst trying to reset it were because a transaction is still in progress.");
358:                    }
359:                }
360:
361:                return !errorsEncountered;
362:            }
363:
364:            private static boolean isTriggerResetException() {
365:                return triggerResetException;
366:            }
367:
368:            /**
369:             * Called by a unit test.
370:             * @param triggerResetException true it we should trigger a pretend exception.
371:             * @see #isTriggerResetException()
372:             */
373:            protected static void setTriggerResetException(
374:                    boolean triggerResetException) {
375:                ConnectionResetter.triggerResetException = triggerResetException;
376:            }
377:        }
378:
379:        /*
380:         Revision history:
381:         $Log: ConnectionResetter.java,v $
382:         Revision 1.16  2006/01/18 14:40:01  billhorsman
383:         Unbundled Jakarta's Commons Logging.
384:
385:         Revision 1.15  2005/10/07 08:21:53  billhorsman
386:         New hook to allow unit tests to trigger a deliberate exception during reset
387:
388:         Revision 1.14  2003/03/10 23:43:10  billhorsman
389:         reapplied checkstyle that i'd inadvertently let
390:         IntelliJ change...
391:
392:         Revision 1.13  2003/03/10 15:26:46  billhorsman
393:         refactoringn of concurrency stuff (and some import
394:         optimisation)
395:
396:         Revision 1.12  2003/03/03 11:11:57  billhorsman
397:         fixed licence
398:
399:         Revision 1.11  2003/02/06 17:41:04  billhorsman
400:         now uses imported logging
401:
402:         Revision 1.10  2003/01/07 17:21:11  billhorsman
403:         If autoCommit is off, all connections are rollbacked.
404:
405:         Revision 1.9  2002/11/13 20:53:16  billhorsman
406:         now checks to see whether is necessary for each property (better logging)
407:
408:         Revision 1.8  2002/11/13 18:27:59  billhorsman
409:         rethink. committing automatically is bad. so now we just
410:         set autoCommit back to true (which might commit anyway but
411:         that's down to the driver). we do the autoCommit last so
412:         that some of the other resets might throw an exception if
413:         there was a pending transaction. (Throwing an exception is
414:         good - pending transactions are bad.)
415:
416:         Revision 1.7  2002/11/12 21:12:21  billhorsman
417:         automatically calls clearWarnings too
418:
419:         Revision 1.6  2002/11/12 21:10:41  billhorsman
420:         Hmm. Now commits any pending transactions automatically when
421:         you close the connection. I'm still pondering whether this is
422:         wise or not. The only other sensible option is to rollback
423:         since I can't find a way of determining whether either is
424:         necessary.
425:
426:         Revision 1.5  2002/11/12 20:24:12  billhorsman
427:         checkstyle
428:
429:         Revision 1.4  2002/11/12 20:18:23  billhorsman
430:         Made connection resetter a bit more friendly. Now, if it encounters any problems during
431:         reset then that connection is thrown away. This is going to cause you problems if you
432:         always close connections in an unstable state (e.g. with transactions open. But then
433:         again, it's better to know about that as soon as possible, right?
434:
435:         Revision 1.3  2002/11/07 18:55:40  billhorsman
436:         demoted log message from info to debug
437:
438:         Revision 1.2  2002/11/07 12:38:04  billhorsman
439:         performance improvement - only reset when it might be necessary
440:
441:         Revision 1.1  2002/11/06 20:25:08  billhorsman
442:         New class responsible for resetting connections when
443:         they are returned to the pool.
444:
445:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.