1 16 17 package org.springframework.jdbc.datasource; 18 19 import java.lang.reflect.InvocationHandler ; 20 import java.lang.reflect.InvocationTargetException ; 21 import java.lang.reflect.Method ; 22 import java.lang.reflect.Proxy ; 23 import java.sql.Connection ; 24 import java.sql.SQLException ; 25 26 import javax.sql.DataSource ; 27 28 import org.apache.commons.logging.Log; 29 import org.apache.commons.logging.LogFactory; 30 31 81 public class LazyConnectionDataSourceProxy extends DelegatingDataSource { 82 83 private static final Log logger = LogFactory.getLog(LazyConnectionDataSourceProxy.class); 84 85 private Boolean defaultAutoCommit; 86 87 private Integer defaultTransactionIsolation; 88 89 90 94 public LazyConnectionDataSourceProxy() { 95 } 96 97 101 public LazyConnectionDataSourceProxy(DataSource targetDataSource) { 102 setTargetDataSource(targetDataSource); 103 afterPropertiesSet(); 104 } 105 106 114 public void setDefaultAutoCommit(boolean defaultAutoCommit) { 115 this.defaultAutoCommit = new Boolean (defaultAutoCommit); 116 } 117 118 126 public void setDefaultTransactionIsolation(int defaultTransactionIsolation) { 127 this.defaultTransactionIsolation = new Integer (defaultTransactionIsolation); 128 } 129 130 public void afterPropertiesSet() { 131 super.afterPropertiesSet(); 132 133 if (this.defaultAutoCommit == null || this.defaultTransactionIsolation == null) { 136 try { 137 Connection con = getTargetDataSource().getConnection(); 138 try { 139 checkDefaultConnectionProperties(con); 140 } 141 finally { 142 con.close(); 143 } 144 } 145 catch (SQLException ex) { 146 logger.warn("Could not retrieve default auto-commit and transaction isolation settings", ex); 147 } 148 } 149 } 150 151 161 protected synchronized void checkDefaultConnectionProperties(Connection con) throws SQLException { 162 if (this.defaultAutoCommit == null) { 163 this.defaultAutoCommit = new Boolean (con.getAutoCommit()); 164 } 165 if (this.defaultTransactionIsolation == null) { 166 this.defaultTransactionIsolation = new Integer (con.getTransactionIsolation()); 167 } 168 } 169 170 173 protected Boolean defaultAutoCommit() { 174 return defaultAutoCommit; 175 } 176 177 180 protected Integer defaultTransactionIsolation() { 181 return defaultTransactionIsolation; 182 } 183 184 185 193 public Connection getConnection() throws SQLException { 194 return (Connection ) Proxy.newProxyInstance( 195 ConnectionProxy.class.getClassLoader(), 196 new Class [] {ConnectionProxy.class}, 197 new LazyConnectionInvocationHandler()); 198 } 199 200 210 public Connection getConnection(String username, String password) throws SQLException { 211 return (Connection ) Proxy.newProxyInstance( 212 ConnectionProxy.class.getClassLoader(), 213 new Class [] {ConnectionProxy.class}, 214 new LazyConnectionInvocationHandler(username, password)); 215 } 216 217 218 222 private class LazyConnectionInvocationHandler implements InvocationHandler { 223 224 private String username; 225 226 private String password; 227 228 private Boolean readOnly = Boolean.FALSE; 229 230 private Integer transactionIsolation; 231 232 private Boolean autoCommit; 233 234 private boolean closed = false; 235 236 private Connection target; 237 238 public LazyConnectionInvocationHandler() { 239 this.autoCommit = defaultAutoCommit(); 240 this.transactionIsolation = defaultTransactionIsolation(); 241 } 242 243 public LazyConnectionInvocationHandler(String username, String password) { 244 this(); 245 this.username = username; 246 this.password = password; 247 } 248 249 public Object invoke(Object proxy, Method method, Object [] args) throws Throwable { 250 252 if (method.getName().equals("getTargetConnection")) { 253 return getTargetConnection(method); 255 } 256 else if (method.getName().equals("equals")) { 257 return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE); 260 } 261 else if (method.getName().equals("hashCode")) { 262 return new Integer (hashCode()); 266 } 267 268 if (!hasTargetConnection()) { 269 273 if (method.getName().equals("toString")) { 274 return "Lazy Connection proxy for target DataSource [" + getTargetDataSource() + "]"; 275 } 276 else if (method.getName().equals("isReadOnly")) { 277 return this.readOnly; 278 } 279 else if (method.getName().equals("setReadOnly")) { 280 this.readOnly = (Boolean ) args[0]; 281 return null; 282 } 283 else if (method.getName().equals("getTransactionIsolation")) { 284 if (this.transactionIsolation != null) { 285 return this.transactionIsolation; 286 } 287 } 290 else if (method.getName().equals("setTransactionIsolation")) { 291 this.transactionIsolation = (Integer ) args[0]; 292 return null; 293 } 294 else if (method.getName().equals("getAutoCommit")) { 295 if (this.autoCommit != null) { 296 return this.autoCommit; 297 } 298 } 301 else if (method.getName().equals("setAutoCommit")) { 302 this.autoCommit = (Boolean ) args[0]; 303 return null; 304 } 305 else if (method.getName().equals("commit")) { 306 return null; 308 } 309 else if (method.getName().equals("rollback")) { 310 return null; 312 } 313 else if (method.getName().equals("getWarnings")) { 314 return null; 315 } 316 else if (method.getName().equals("clearWarnings")) { 317 return null; 318 } 319 else if (method.getName().equals("isClosed")) { 320 return (this.closed ? Boolean.TRUE : Boolean.FALSE); 321 } 322 else if (method.getName().equals("close")) { 323 this.closed = true; 325 return null; 326 } 327 else if (this.closed) { 328 throw new SQLException ("Illegal operation: connection is closed"); 331 } 332 } 333 334 try { 338 return method.invoke(getTargetConnection(method), args); 339 } 340 catch (InvocationTargetException ex) { 341 throw ex.getTargetException(); 342 } 343 } 344 345 348 private boolean hasTargetConnection() { 349 return (this.target != null); 350 } 351 352 355 private Connection getTargetConnection(Method operation) throws SQLException { 356 if (this.target == null) { 357 if (logger.isDebugEnabled()) { 359 logger.debug("Connecting to database for operation '" + operation.getName() + "'"); 360 } 361 362 this.target = (this.username != null) ? 364 getTargetDataSource().getConnection(this.username, this.password) : 365 getTargetDataSource().getConnection(); 366 367 checkDefaultConnectionProperties(this.target); 369 370 if (this.readOnly.booleanValue()) { 372 this.target.setReadOnly(this.readOnly.booleanValue()); 373 } 374 if (this.transactionIsolation != null && 375 !this.transactionIsolation.equals(defaultTransactionIsolation())) { 376 this.target.setTransactionIsolation(this.transactionIsolation.intValue()); 377 } 378 if (this.autoCommit != null && this.autoCommit.booleanValue() != this.target.getAutoCommit()) { 379 this.target.setAutoCommit(this.autoCommit.booleanValue()); 380 } 381 } 382 383 else { 384 if (logger.isDebugEnabled()) { 386 logger.debug("Using existing database connection for operation '" + operation.getName() + "'"); 387 } 388 } 389 390 return this.target; 391 } 392 } 393 394 } 395 | Popular Tags |