1 6 package org.logicalcobwebs.proxool; 7 8 import org.apache.commons.logging.Log; 9 import org.apache.commons.logging.Log; 10 11 import java.lang.reflect.Method ; 12 import java.sql.Connection ; 13 import java.sql.SQLException ; 14 import java.util.HashMap ; 15 import java.util.HashSet ; 16 import java.util.Iterator ; 17 import java.util.Map ; 18 import java.util.Set ; 19 20 31 public class ConnectionResetter { 32 33 private Log log; 34 35 38 private boolean initialised; 39 40 44 private Map accessorMutatorMap = new HashMap (); 45 46 50 private Map defaultValues = new HashMap (); 51 52 55 protected static final String MUTATOR_PREFIX = "set"; 56 57 private String driverName; 58 59 62 protected static boolean triggerResetException; 63 64 68 protected ConnectionResetter(Log log, String driverName) { 69 this.log = log; 70 this.driverName = driverName; 71 72 addReset("getCatalog", "setCatalog"); 74 addReset("isReadOnly", "setReadOnly"); 75 addReset("getTransactionIsolation", "setTransactionIsolation"); 76 addReset("getTypeMap", "setTypeMap"); 77 addReset("getHoldability", "setHoldability"); 78 } 79 80 86 private void addReset(String accessorName, String mutatorName) { 87 88 try { 89 90 Method accessor = null; 91 Method mutator = null; 92 93 Method [] methods = Connection .class.getMethods(); 94 for (int i = 0; i < methods.length; i++) { 95 Method method = methods[i]; 96 if (method.getName().equals(accessorName)) { 97 if (accessor == null) { 98 accessor = method; 99 } else { 100 log.info("Skipping ambiguous reset method " + accessorName); 101 return; 102 } 103 } 104 if (method.getName().equals(mutatorName)) { 105 if (mutator == null) { 106 mutator = method; 107 } else { 108 log.info("Skipping ambiguous reset method " + mutatorName); 109 return; 110 } 111 } 112 } 113 114 if (accessor == null) { 115 log.debug("Ignoring attempt to map reset method " + accessorName + " (probably because it isn't implemented in this JDK)"); 116 } else if (mutator == null) { 117 log.debug("Ignoring attempt to map reset method " + mutatorName + " (probably because it isn't implemented in this JDK)"); 118 } else if (accessorMutatorMap.containsKey(accessor)) { 119 log.warn("Ignoring attempt to map duplicate reset method " + accessorName); 120 } else if (accessorMutatorMap.containsValue(mutator)) { 121 log.warn("Ignoring attempt to map duplicate reset method " + mutatorName); 122 } else { 123 124 if (mutatorName.indexOf(MUTATOR_PREFIX) != 0) { 125 log.warn("Resetter mutator " + mutatorName + " does not start with " + MUTATOR_PREFIX 126 + " as expected. Proxool maynot recognise that a reset is necessary."); 127 } 128 129 if (accessor.getParameterTypes().length > 0) { 130 log.info("Ignoring attempt to map accessor method " + accessorName + ". It must have no arguments."); 131 } else if (mutator.getParameterTypes().length != 1) { 132 log.info("Ignoring attempt to map mutator method " + mutatorName 133 + ". It must have exactly one argument, not " + mutator.getParameterTypes().length); 134 } else { 135 accessorMutatorMap.put(accessor, mutator); 136 } 137 } 138 } catch (Exception e) { 139 log.error("Problem mapping " + accessorName + " and " + mutatorName, e); 140 } 141 142 } 143 144 149 protected void initialise(Connection connection) { 150 if (!initialised) { 151 synchronized (this) { 152 if (!initialised) { 153 154 Set accessorsToRemove = new HashSet (); 155 Iterator i = accessorMutatorMap.keySet().iterator(); 156 while (i.hasNext()) { 157 Method accessor = (Method ) i.next(); 158 Method mutator = (Method ) accessorMutatorMap.get(accessor); 159 Object value = null; 160 try { 161 value = accessor.invoke(connection, null); 162 if (value != null) { 165 defaultValues.put(mutator, value); 166 } 167 if (log.isDebugEnabled()) { 168 log.debug("Remembering default value: " + accessor.getName() + "() = " + value); 169 } 170 171 } catch (Throwable t) { 172 log.debug(driverName + " does not support " + accessor.getName() + ". Proxool doesn't mind."); 173 accessorsToRemove.add(accessor); 175 } 176 177 try { 180 Object [] args = {value}; 181 mutator.invoke(connection, args); 182 } catch (Throwable t) { 183 log.debug(driverName + " does not support " + mutator.getName() + ". Proxool doesn't mind."); 184 accessorsToRemove.add(accessor); 186 } 187 188 } 189 190 Iterator j = accessorsToRemove.iterator(); 192 while (j.hasNext()) { 193 Method accessor = (Method ) j.next(); 194 Method mutator = (Method ) accessorMutatorMap.get(accessor); 195 accessorMutatorMap.remove(accessor); 196 defaultValues.remove(mutator); 197 } 198 199 initialised = true; 200 } 201 } 202 } 203 } 204 205 212 protected boolean reset(Connection connection, String id) { 213 boolean errorsEncountered = false; 214 215 try { 216 connection.clearWarnings(); 217 } catch (SQLException e) { 218 errorsEncountered = true; 219 log.warn(id + " - Problem calling connection.clearWarnings()", e); 220 } 221 222 boolean autoCommit = true; 224 try { 225 autoCommit = connection.getAutoCommit(); 226 } catch (SQLException e) { 227 errorsEncountered = true; 228 log.warn(id + " - Problem calling connection.getAutoCommit()", e); 229 } 230 231 244 if (!autoCommit) { 245 try { 246 connection.rollback(); 247 } catch (SQLException e) { 248 log.error("Unexpected exception whilst calling rollback during connection reset", e); 249 } 250 } 251 252 Iterator i = accessorMutatorMap.keySet().iterator(); 259 while (i.hasNext()) { 260 Method accessor = (Method ) i.next(); 261 Method mutator = (Method ) accessorMutatorMap.get(accessor); 262 Object [] args = {defaultValues.get(mutator)}; 263 try { 264 Object currentValue = accessor.invoke(connection, null); 265 if (currentValue == null && args[0] == null) { 266 } else if (currentValue.equals(args[0])) { 268 } else { 270 mutator.invoke(connection, args); 271 if (log.isDebugEnabled()) { 272 log.debug(id + " - Reset: " + mutator.getName() + "(" + args[0] + ") from " + currentValue); 273 } 274 } 275 } catch (Throwable t) { 276 errorsEncountered = true; 277 if (log.isDebugEnabled()) { 278 log.debug(id + " - Problem resetting: " + mutator.getName() + "(" + args[0] + ").", t); 279 } 280 } 281 } 282 283 if (!autoCommit) { 285 try { 286 connection.setAutoCommit(true); 289 log.debug(id + " - autoCommit reset back to true"); 290 } catch (Throwable t) { 291 errorsEncountered = true; 292 log.warn(id + " - Problem calling connection.commit() or connection.setAutoCommit(true)", t); 293 } 294 } 295 296 if (isTriggerResetException()) { 297 log.warn("Triggering pretend exception during reset"); 298 errorsEncountered = true; 299 } 300 301 if (errorsEncountered) { 302 303 log.warn(id + " - There were some problems resetting the connection (see debug output for details). It will not be used again " 304 + "(just in case). The thread that is responsible is named '" + Thread.currentThread().getName() + "'"); 305 if (!autoCommit) { 306 log.warn(id + " - The connection was closed with autoCommit=false. That is fine, but it might indicate that " 307 + "the problems that happened whilst trying to reset it were because a transaction is still in progress."); 308 } 309 } 310 311 return !errorsEncountered; 312 } 313 314 private static boolean isTriggerResetException() { 315 return triggerResetException; 316 } 317 318 323 protected static void setTriggerResetException(boolean triggerResetException) { 324 ConnectionResetter.triggerResetException = triggerResetException; 325 } 326 } 327 328 395 | Popular Tags |