1 package org.jahia.services.database; 2 3 import java.io.PrintWriter ; 4 import java.io.StringWriter ; 5 import java.sql.Connection ; 6 import java.sql.DriverManager ; 7 import java.sql.SQLException ; 8 import java.util.Vector ; 9 10 21 public class ConnectionPool implements Runnable 22 { 23 private static org.apache.log4j.Logger logger = 24 org.apache.log4j.Logger.getLogger(ConnectionPool.class); 25 26 private String db_driver; 27 private String db_url; 28 private String db_username; 29 private String db_password; 30 private int minConnections; 31 private int maxConnections; 32 private boolean waitIfBusy; 33 private long waitTimeOut = 60*1000; private int maxTries = 10; 36 private Vector availableConnections = new Vector (); 38 39 private Vector busyConnections = new Vector (); 42 43 private boolean connectionPending = false; 46 47 private boolean verbose = true; 49 50 private boolean veryVerbose = false; 52 53 71 public ConnectionPool( String db_driver, 72 String db_url, 73 String db_username, 74 String db_password, 75 int initialConnections, 76 int maxConnections, 77 boolean waitIfBusy, 78 boolean verbose, 79 boolean veryVerbose ) 80 throws SQLException 81 { 82 if (verbose) { 83 logger.debug("New connection pool object in creation... "); 84 } 85 this.db_driver = db_driver; 87 this.db_url = db_url; 88 this.db_username = db_username; 89 this.db_password = db_password; 90 this.minConnections = initialConnections; 91 this.maxConnections = maxConnections; 92 this.waitIfBusy = waitIfBusy; 93 this.verbose = verbose; 94 this.veryVerbose = veryVerbose; 95 96 if (verbose) { 97 logger.debug("verbose is " + verbose); 98 } 99 if (initialConnections > maxConnections) { 101 initialConnections = maxConnections; 102 } 103 104 availableConnections = new Vector (initialConnections); 105 106 for (int i=0; i < initialConnections; i++) { 108 availableConnections.addElement( makeNewConnection() ); 109 } 110 111 } 113 114 115 131 protected synchronized Connection getConnection(int debugID) 132 throws SQLException 133 { 134 int tryCount = 0; 135 while (true) { 136 tryCount++; 137 if (tryCount > maxTries) { 138 if (verbose) { 139 logger.debug("Maximum try count (" + maxTries + ") reached while trying to retrieve a connection. Failing call."); 140 } 141 throw new SQLException ("Maximum try count (" + maxTries + ") reached while trying to retrieve a connection. Failing call."); 142 } 143 if (verbose) { 144 logger.debug("Trying to get a database connection (DEBUGID="+debugID+", available=" + 145 availableConnections.size() + ", busy=" + 146 busyConnections.size() + ", try=" + tryCount + ")" 147 ); 148 } 149 150 if (getTotalConnections() < minConnections) { 152 if (verbose) { 153 logger.debug("Warning : current number of connnections below minimum pool size !"); 154 } 155 } 156 157 if (!availableConnections.isEmpty()) { 159 Connection existingConnection = (Connection ) availableConnections.lastElement(); 161 int lastIndex = availableConnections.size() - 1; 162 availableConnections.removeElementAt( lastIndex ); 164 if (existingConnection.isClosed()) { 166 if (verbose) { 167 logger.debug("Connection retrieved from available connection is already closed, waiting for a new one ..."); 168 } 169 notifyAll(); 171 if (verbose) { 173 logger.debug("looping to wait for a connection that isn't already closed..."); 174 } 175 continue; 176 } else { 177 busyConnections.addElement( existingConnection ); 180 return existingConnection; 181 } 182 } else { 183 if ((getTotalConnections() < maxConnections) && (!connectionPending)) { 186 makeBackgroundConnection(); 188 } else if (!waitIfBusy) { 189 throw new SQLException ( "Connection limit reached" ); 193 } 194 try { 196 if (verbose) { 198 logger.debug("Waiting for a connection to be freed..."); 199 } 200 wait(waitTimeOut); 201 if (verbose) { 202 logger.debug("Awoke from waiting for available connection..."); 203 } 204 } catch (InterruptedException ie) { 205 if (verbose) { 207 logger.debug("Interruption timeout while waiting for free connection.", ie); 208 } 209 } 210 } 211 if (verbose) { 212 logger.debug("looping to wait for a connection..."); 213 } 214 } } 217 218 219 223 private void makeBackgroundConnection() 224 { 225 if (verbose) { 226 logger.debug("Creating a background Connection via a thread"); 227 } 228 connectionPending = true; 230 try { 232 Thread connectionThread = new Thread ( this ); 233 connectionThread.start(); } catch (OutOfMemoryError memError) { 235 logger.debug("Out of memory exception during background thread connnection creation", memError); 236 } 238 } 240 241 242 247 public void run() 248 { 249 if (verbose) { 250 logger.debug("Starting a new ConnectionPool Thread to create a database connnection"); 251 } 252 try { 253 Connection newConnection = makeNewConnection(); 255 synchronized( this ) { 256 availableConnections.addElement( newConnection ); 258 connectionPending = false; 260 notifyAll(); 262 } 263 } catch (Throwable t) { 264 logger.debug("Exception while trying to open connection to the database", t); 265 } 268 } 270 271 277 private Connection makeNewConnection() 278 throws SQLException 279 { 280 if (verbose) { 281 logger.debug("Creating a new connection"); 282 } 283 try { 284 Class.forName( db_driver ); 286 if (veryVerbose) { 288 PrintWriter databaseLog = new PrintWriter (System.out); 289 DriverManager.setLogWriter(databaseLog); 290 } 291 Connection newConnection = DriverManager.getConnection( db_url, db_username, db_password ); 292 return newConnection; 293 } catch (ClassNotFoundException cnfe) { 294 StringWriter strWriter = new StringWriter (); 296 PrintWriter ptrWriter = new PrintWriter (strWriter); 297 cnfe.printStackTrace(ptrWriter); 298 throw new SQLException ( "Can't find class to driver : " + db_driver + " exception:" + strWriter.toString()); 299 } 300 } 302 309 protected synchronized void free( Connection theConnection ) 310 { 311 if (verbose) { 312 logger.debug("Trying to free a connection (available : " 313 + availableConnections.size() + 314 "; busy : " + busyConnections.size() + ")"); 315 } 316 busyConnections.removeElement( theConnection ); 318 try { 319 if (!theConnection.isClosed()) { 320 if (!availableConnections.contains(theConnection)) { 321 availableConnections.addElement(theConnection); 323 } else { 324 logger.debug("Connection is already present in pool, ignoring second insert."); 325 } 326 } else { 327 if (verbose) { 328 logger.debug("Freeing an already closed connection, we won't add it to the available connection list."); 329 } 330 } 331 notifyAll(); 333 } catch (SQLException sqle) { 334 logger.debug("Error while testing if connection is closed", sqle); 335 } 336 } 338 339 340 348 public synchronized int getTotalConnections() 349 { 350 return ( availableConnections.size() + busyConnections.size() ); 351 } 353 354 359 public int getNbFreeConnections() 360 { 361 return ( availableConnections.size() ); 362 } 364 365 370 public int getBusyConnections() { 371 return busyConnections.size(); 372 } 373 374 379 public int getMinConnections() { 380 return this.minConnections; 381 } 382 383 388 public int getMaxConnections() { 389 return this.maxConnections; 390 } 391 392 393 399 public synchronized void closeAllConnections() 400 { 401 if (verbose) { 402 logger.debug("Closing all connections !"); 403 } 404 closeConnections( availableConnections ); 405 availableConnections = new Vector (); 406 closeConnections( busyConnections ); 407 busyConnections = new Vector (); 408 } 410 411 412 416 private void closeConnections( Vector connections ) 417 { 418 if (verbose) { 419 logger.debug("Closing " + connections.size() + " connections"); 420 } 421 try { 422 for (int i=0; i < connections.size(); i++) { 423 Connection theConnection = (Connection ) connections.elementAt( i ); 424 if (!theConnection.isClosed()) { 425 theConnection.close(); 426 } 427 } 428 } catch (SQLException se) { 429 logger.debug("Error while closing connection", se); 430 } 432 } 434 } 435 | Popular Tags |