1 5 package snaq.db; 6 7 import snaq.util.*; 8 import java.sql.*; 9 import java.util.*; 10 11 18 public class ConnectionPool extends ObjectPool implements Comparable 19 { 20 private String url, user, pass; 21 private Properties props; 22 private ConnectionValidator validator = new DefaultValidator(); 23 private PasswordDecoder decoder; 24 private boolean cacheSS, cachePS, cacheCS; 25 private List listeners = new ArrayList(); 26 27 28 38 public ConnectionPool(String name, int poolSize, int maxSize, long expiryTime, String url, String username, String password) 39 { 40 super(name, poolSize, maxSize, expiryTime); 41 this.url = url; 42 this.user = username; 43 this.pass = password; 44 this.props = null; 45 setCaching(true); 46 addObjectPoolListener(new EventRelay()); 47 } 48 49 58 public ConnectionPool(String name, int poolSize, int maxSize, long expiryTime, String url, Properties props) 59 { 60 this(name, poolSize, maxSize, expiryTime, url, null, null); 61 this.props = props; 62 this.pass = props.getProperty("password"); 63 addObjectPoolListener(new EventRelay()); 64 } 65 66 67 70 protected Reusable create() throws SQLException 71 { 72 Connection con = null; 73 CacheConnection ccon = null; 74 try 75 { 76 if (props != null) 77 { 78 if (decoder != null) 79 props.setProperty("password", new String (decoder.decode(pass))); 80 log("Getting connection (properties): " + url); 81 con = DriverManager.getConnection(url, props); 82 } 83 else if (user != null) 84 { 85 try 86 { 87 if (decoder != null) 88 { 89 log("Getting connection (user/enc.pass): " + url); 90 con = DriverManager.getConnection(url, user, new String (decoder.decode(pass))); 91 } 92 else 93 { 94 log("Getting connection (user/pass): " + url); 95 con = DriverManager.getConnection(url, user, pass); 96 } 97 } 98 catch (SQLException sqle) 99 { 100 log("Failed to connect with standard authentication...trying with just JDBC URL"); 101 log("Getting connection (URL only): " + url); 102 con = DriverManager.getConnection(url); 103 } 104 } 105 else 106 con = DriverManager.getConnection(url); 107 108 ccon = new CacheConnection(this, con); 110 ccon.setCacheStatements(cacheSS); 111 ccon.setCachePreparedStatements(cachePS); 112 ccon.setCacheCallableStatements(cacheCS); 113 log("Created a new connection"); 114 115 SQLWarning warn = con.getWarnings(); 117 while (warn != null) 118 { 119 log("Warning - " + warn.getMessage()); 120 warn = warn.getNextWarning(); 121 } 122 } 123 catch (SQLException sqle) 124 { 125 log(sqle, "Can't create a new connection for " + url); 126 try { con.close(); } 128 catch (SQLException sqle2) {} 129 throw sqle; 131 } 132 return ccon; 133 } 134 135 138 protected boolean isValid(final Reusable o) 139 { 140 if (o == null) 141 return false; 142 if (validator == null) 143 return true; 144 145 try 146 { 147 boolean valid = validator.isValid((Connection)o); 148 if (!valid) 149 fireValidationErrorEvent(); 150 return valid; 151 } 152 catch (Exception e) { log(e, "Exception during validation"); return false; } 153 } 154 155 158 public void setValidator(ConnectionValidator cv) { validator = cv; } 159 160 163 public ConnectionValidator getValidator() { return validator; } 164 165 168 public void setPasswordDecoder(PasswordDecoder pd) { decoder = pd; } 169 170 173 public PasswordDecoder getPasswordDecoder() { return decoder; } 174 175 178 protected void destroy(final Reusable o) 179 { 180 if (o == null) 181 return; 182 try 183 { 184 ((CacheConnection)o).release(); 185 log("Destroyed connection"); 186 } 187 catch (SQLException e) 188 { 189 log(e, "Can't destroy connection"); 190 } 191 } 192 193 196 public Connection getConnection() throws SQLException 197 { 198 try 199 { 200 Reusable o = super.checkOut(); 201 if (o != null) 202 { 203 CacheConnection cc = (CacheConnection)o; 204 cc.setOpen(); 205 return cc; 206 } 207 return null; 208 } 209 catch (Exception e) 210 { 211 log(e, "Error getting connection"); 212 if (e instanceof SQLException) 213 throw (SQLException)e; 214 else 215 { 216 Throwable t = e.getCause(); 217 while (t != null) 218 { 219 log(e, "Error getting connection"); 220 t = t.getCause(); 221 } 222 throw new SQLException(e.getMessage()); 223 } 224 } 225 } 226 227 230 public Connection getConnection(long timeout) throws SQLException 231 { 232 try 233 { 234 Object o = super.checkOut(timeout); 235 if (o != null) 236 { 237 CacheConnection cc = (CacheConnection)o; 238 cc.setOpen(); 239 return cc; 240 } 241 return null; 242 } 243 catch (Exception e) 244 { 245 if (e instanceof SQLException) 246 throw (SQLException)e; 247 else 248 { 249 log(e, "Error getting connection"); 250 throw new SQLException(e.getMessage()); 251 } 252 } 253 } 254 255 260 protected void freeConnection(Connection c) throws SQLException 261 { 262 if (c == null || !CacheConnection.class.isInstance(c)) 263 log("Attempt to return invalid item"); 264 else 265 { 266 CacheConnection cc = (CacheConnection)c; 267 super.checkIn((Reusable)c); 268 } 269 } 270 271 275 public void setCaching(boolean b) 276 { 277 cacheSS = cachePS = cacheCS = b; 278 } 279 280 286 public void setCaching(boolean ss, boolean ps, boolean cs) 287 { 288 cacheSS = ss; 289 cachePS = ps; 290 cacheCS = cs; 291 } 292 293 294 public String toString() { return getName(); } 295 296 public int compareTo(Object o) { return this.toString().compareTo(((ConnectionPool)o).toString()); } 297 298 302 305 public final void addConnectionPoolListener(ConnectionPoolListener x) 306 { 307 listeners.add(x); 308 } 309 310 313 public final void removeConnectionPoolListener(ConnectionPoolListener x) 314 { 315 listeners.remove(x); 316 } 317 318 private final void fireValidationErrorEvent() 319 { 320 if (listeners.isEmpty()) 321 return; 322 ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.VALIDATION_ERROR); 323 for (Iterator iter = listeners.iterator(); iter.hasNext();) 324 ((ConnectionPoolListener)iter.next()).validationError(poolEvent); 325 } 326 327 private final void firePoolCheckOutEvent() 328 { 329 if (listeners.isEmpty()) 330 return; 331 ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.CHECKOUT); 332 for (Iterator iter = listeners.iterator(); iter.hasNext();) 333 ((ConnectionPoolListener)iter.next()).poolCheckOut(poolEvent); 334 } 335 336 private final void firePoolCheckInEvent() 337 { 338 if (listeners.isEmpty()) 339 return; 340 ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.CHECKIN); 341 for (Iterator iter = listeners.iterator(); iter.hasNext();) 342 ((ConnectionPoolListener)iter.next()).poolCheckIn(poolEvent); 343 } 344 345 private final void fireMaxPoolLimitReachedEvent() 346 { 347 if (listeners.isEmpty()) 348 return; 349 ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.MAX_POOL_LIMIT_REACHED); 350 for (Iterator iter = listeners.iterator(); iter.hasNext();) 351 ((ConnectionPoolListener)iter.next()).maxPoolLimitReached(poolEvent); 352 } 353 354 private final void fireMaxPoolLimitExceededEvent() 355 { 356 if (listeners.isEmpty()) 357 return; 358 ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.MAX_POOL_LIMIT_EXCEEDED); 359 for (Iterator iter = listeners.iterator(); iter.hasNext();) 360 ((ConnectionPoolListener)iter.next()).maxPoolLimitExceeded(poolEvent); 361 } 362 363 private final void fireMaxSizeLimitReachedEvent() 364 { 365 if (listeners.isEmpty()) 366 return; 367 ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.MAX_SIZE_LIMIT_REACHED); 368 for (Iterator iter = listeners.iterator(); iter.hasNext();) 369 ((ConnectionPoolListener)iter.next()).maxSizeLimitReached(poolEvent); 370 } 371 372 private final void fireMaxSizeLimitErrorEvent() 373 { 374 if (listeners.isEmpty()) 375 return; 376 ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.MAX_SIZE_LIMIT_ERROR); 377 for (Iterator iter = listeners.iterator(); iter.hasNext();) 378 ((ConnectionPoolListener)iter.next()).maxSizeLimitError(poolEvent); 379 } 380 381 private final void fireParametersChangedEvent() 382 { 383 if (listeners == null || listeners.isEmpty()) 384 return; 385 ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.PARAMETERS_CHANGED); 386 for (Iterator iter = listeners.iterator(); iter.hasNext();) 387 ((ConnectionPoolListener)iter.next()).poolParametersChanged(poolEvent); 388 } 389 390 private final void firePoolReleasedEvent() 391 { 392 if (listeners.isEmpty()) 393 return; 394 ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.POOL_RELEASED); 395 for (Iterator iter = listeners.iterator(); iter.hasNext();) 396 ((ConnectionPoolListener)iter.next()).poolReleased(poolEvent); 397 } 398 399 400 403 private final class EventRelay extends ObjectPoolEventAdapter 404 { 405 public void poolCheckOut(ObjectPoolEvent evt) { firePoolCheckOutEvent(); } 406 public void poolCheckIn(ObjectPoolEvent evt) { firePoolCheckInEvent(); } 407 public void maxPoolLimitReached(ObjectPoolEvent evt) { fireMaxPoolLimitReachedEvent(); } 408 public void maxPoolLimitExceeded(ObjectPoolEvent evt) { fireMaxPoolLimitExceededEvent(); } 409 public void maxSizeLimitReached(ObjectPoolEvent evt) { fireMaxSizeLimitReachedEvent(); } 410 public void maxSizeLimitError(ObjectPoolEvent evt) { fireMaxSizeLimitErrorEvent(); } 411 public void poolParametersChanged(ObjectPoolEvent evt) { fireParametersChangedEvent(); } 412 public void poolReleased(ObjectPoolEvent evt) { firePoolReleasedEvent(); listeners.clear(); } 413 } 414 415 416 420 static class DefaultValidator implements ConnectionValidator 421 { 422 425 public boolean isValid(Connection con) 426 { 427 try { return !con.isClosed(); } 428 catch (SQLException e) { return false; } 429 } 430 } 431 } | Popular Tags |