1 5 package snaq.db; 6 7 import java.io.*; 8 import java.sql.*; 9 import java.text.*; 10 import java.util.*; 11 import snaq.util.LogUtil; 12 13 95 public final class ConnectionPoolManager extends LogUtil implements Comparable 96 { 97 private static final String PROPERTIES_INSTANCE_KEY = "PROPERTIES_INSTANCE"; 98 private static final String DEFAULT_PROPERTIES_FILE = "/dbpool.properties"; 99 private static Hashtable managers = new Hashtable(); 100 101 private static ArrayList drivers = new ArrayList(); 102 private boolean released = false; 103 private HashMap pools = new HashMap(); 104 protected int clients; 105 private Object source, key; 106 107 108 private ConnectionPoolManager(Properties props, Object src) 109 { 110 super(); 111 this.source = src; 112 init(props); 113 } 114 115 116 public String toString() 117 { 118 if (source instanceof String ) 119 return "ConnectionPoolManager [CLASSPATH resource:" + source + "]"; 120 else if (source instanceof File) 121 return "ConnectionPoolManager [File:" + ((File)source).getAbsolutePath() + "]"; 122 else if (source instanceof Properties) 123 return "ConnectionPoolManager [Properties]"; 124 else 125 return "ConnectionPoolManager [Unknown]"; 126 } 127 128 129 public int compareTo(Object o) { return this.toString().compareTo(((ConnectionPoolManager)o).toString()); } 130 131 138 public static Enumeration instances() { return Collections.enumeration(getInstances()); } 139 140 147 public static Set getInstances() 148 { 149 Set x = new HashSet(); 150 x.addAll(managers.values()); 151 return x; 152 } 153 154 160 public static synchronized ConnectionPoolManager getInstance(String propsFile) throws IOException 161 { 162 String s = propsFile.startsWith("/") ? propsFile : ("/" + propsFile); 163 Object o = managers.get(s); 164 ConnectionPoolManager cpm = (o != null) ? (ConnectionPoolManager)o : null; 165 if (cpm == null || cpm.isReleased()) 166 { 167 cpm = new ConnectionPoolManager(loadProperties(s), propsFile); 168 cpm.key = s; 169 managers.put(cpm.key, cpm); 170 } 171 cpm.clients++; 172 return cpm; 173 } 174 175 181 public static synchronized ConnectionPoolManager getInstance(File propsFile) throws IOException 182 { 183 Object o = managers.get(propsFile); 184 ConnectionPoolManager cpm = (o != null) ? (ConnectionPoolManager)o : null; 185 if (cpm == null || cpm.isReleased()) 186 { 187 try 188 { 189 cpm = new ConnectionPoolManager(loadProperties(propsFile), propsFile); 190 cpm.key = propsFile; 191 managers.put(cpm.key, cpm); 192 } 193 catch (IOException ioe) 194 { 195 if (ioe instanceof FileNotFoundException) 196 System.err.println("Unable to find the properties file " + propsFile.getAbsolutePath()); 197 else 198 System.err.println("Error loading the properties file " + propsFile.getAbsolutePath()); 199 ioe.printStackTrace(); 200 return null; 201 } 202 } 203 cpm.clients++; 204 return cpm; 205 } 206 207 214 public static synchronized ConnectionPoolManager getInstance() throws IOException 215 { 216 Object o = managers.get(PROPERTIES_INSTANCE_KEY); 217 ConnectionPoolManager cpm = (o != null) ? (ConnectionPoolManager)o : null; 218 if (cpm != null && !cpm.released) 219 cpm.clients++; 220 else 221 cpm = getInstance(DEFAULT_PROPERTIES_FILE); 222 223 return cpm; 224 } 225 226 237 public static synchronized void createInstance(Properties props) 238 { 239 Object o = managers.get(DEFAULT_PROPERTIES_FILE); 241 ConnectionPoolManager cpm = (o != null) ? (ConnectionPoolManager)o : null; 242 if (cpm != null && !cpm.isReleased()) 243 throw new RuntimeException ("Default properties file instance already exists"); 244 245 cpm = new ConnectionPoolManager(props, props); 247 cpm.key = PROPERTIES_INSTANCE_KEY; 248 managers.put(cpm.key, cpm); 249 } 250 251 254 private static Properties loadProperties(File propsFile) throws IOException 255 { 256 if (!propsFile.exists()) 257 throw new FileNotFoundException(propsFile.getAbsolutePath() + " does not exist"); 258 if (propsFile.isDirectory()) 259 throw new IOException("Error accessing properties file - " + propsFile.getAbsolutePath() + " is a directory"); 260 InputStream is = new FileInputStream(propsFile); 261 Properties props = new Properties(); 262 props.load(is); 263 is.close(); 264 return props; 265 } 266 267 272 private static Properties loadProperties(String propsResource) throws IOException 273 { 274 InputStream is = ConnectionPoolManager.class.getResourceAsStream(propsResource); 275 Properties props = new Properties(); 276 try 277 { 278 props.load(is); 279 } 280 catch (IOException ioe) 281 { 282 System.err.println("Unable to load the properties file. Make sure " + propsResource + " is in the CLASSPATH."); 283 ioe.printStackTrace(); 284 throw ioe; 285 } 286 return props; 287 } 288 289 292 private void init(Properties props) 293 { 294 String logFile = props.getProperty("logfile", "ConnectionPoolManager.log"); 295 String df = props.getProperty("dateformat", "EEE MMM dd hh:mm:ss.SSS ZZZ yyyy"); 296 try 297 { 298 setDateFormat(new SimpleDateFormat(df)); 299 setLog(new FileOutputStream(logFile, true)); 300 } 301 catch (IOException e) 302 { 303 System.err.println("Can't open the log file: " + logFile); 304 } 305 loadDrivers(props); 306 createPools(props); 307 } 308 309 315 private void loadDrivers(Properties props) 316 { 317 String driverClasses = props.getProperty("drivers"); 318 StringTokenizer st = new StringTokenizer(driverClasses, ",: \t\n\r\f"); 319 Enumeration current = DriverManager.getDrivers(); 320 while (st.hasMoreElements()) 321 { 322 String driverClassName = st.nextToken().trim(); 323 try 324 { 325 boolean using = false; 327 while (current.hasMoreElements()) 328 { 329 String cName = current.nextElement().getClass().getName(); 330 if (cName.equals(driverClassName)) 331 using = true; 332 } 333 if (!using) 334 { 335 Driver driver = (Driver)Class.forName(driverClassName).newInstance(); 336 DriverManager.registerDriver(driver); 337 drivers.add(driver); 338 log("Registered JDBC driver " + driverClassName); 339 } 340 } 341 catch (Exception e) 342 { 343 log("Unable to register JDBC driver: " + driverClassName + ", Exception: " + e); 344 } 345 } 346 } 347 348 352 private void createPools(Properties props) 353 { 354 Iterator iter = props.keySet().iterator(); 355 while (iter.hasNext()) 356 { 357 String name = (String )iter.next(); 358 if (name.endsWith(".url")) 359 { 360 String poolName = name.substring(0, name.lastIndexOf(".")); 361 String url = props.getProperty(poolName + ".url"); 362 if (url == null) 363 { 364 log("No URL specified for " + poolName); 365 continue; 366 } 367 368 String user = props.getProperty(poolName + ".user"); 369 user = (user != null) ? user.trim() : user; 370 String pass = props.getProperty(poolName + ".password"); 371 pass = (pass != null) ? pass.trim() : pass; 372 String poolSize = props.getProperty(poolName + ".maxpool", "0").trim(); 373 String maxSize = props.getProperty(poolName + ".maxconn", "0").trim(); 374 String init = props.getProperty(poolName + ".init", "0").trim(); 375 String expiry = props.getProperty(poolName + ".expiry", "0").trim(); 376 String validator = props.getProperty(poolName + ".validator"); 377 String decoder = props.getProperty(poolName + ".decoder"); 378 String logFile = props.getProperty(poolName + ".logfile"); 379 String dateformat = props.getProperty(poolName + ".dateformat"); 380 validator = (validator != null) ? validator.trim() : validator; 381 boolean noCache = props.getProperty(poolName + ".cache", "true").trim().equalsIgnoreCase("false"); 382 boolean async = props.getProperty(poolName + ".async", "false").trim().equalsIgnoreCase("true"); 383 boolean poolDebug = props.getProperty(poolName + ".debug", "false").trim().equalsIgnoreCase("true"); 384 385 Properties poolProps = new Properties(); 387 String prefix = poolName + ".prop."; 388 Iterator it = props.keySet().iterator(); 389 while (it.hasNext()) 390 { 391 String s = (String )it.next(); 392 if (s.startsWith(prefix)) 393 poolProps.setProperty(s.substring(prefix.length()), props.getProperty(s)); 394 } 395 if (!poolProps.isEmpty() && user != null && !user.equals("")) 396 { 397 poolProps.setProperty("user", user); 398 poolProps.setProperty("password", pass); 399 } 400 else 401 poolProps = null; 402 403 int pSize, mSize, iSize, exp; 405 try { pSize = Integer.valueOf(poolSize).intValue(); } 406 catch (NumberFormatException nfe) 407 { 408 log("Invalid maxpool value " + poolSize + " for " + poolName); 409 pSize = 0; 410 } 411 try { mSize = Integer.valueOf(maxSize).intValue(); } 413 catch (NumberFormatException nfe) 414 { 415 log("Invalid maxconn value " + maxSize + " for " + poolName); 416 mSize = 0; 417 } 418 try { iSize = Integer.valueOf(init).intValue(); } 420 catch (NumberFormatException nfe) 421 { 422 log("Invalid initsize value " + init + " for " + poolName); 423 iSize = 0; 424 } 425 try { exp = Integer.valueOf(expiry).intValue(); } 427 catch (NumberFormatException nfe) 428 { 429 log("Invalid expiry value " + expiry + " for " + poolName); 430 exp = 0; 431 } 432 433 pSize = Math.max(pSize, 0); mSize = Math.max(mSize, 0); if (mSize > 0) mSize = Math.max(mSize, pSize); 438 iSize = Math.min(Math.max(iSize, 0), pSize); exp = Math.max(exp, 0); 441 ConnectionPool pool = null; 443 if (poolProps != null) 444 pool = new ConnectionPool(poolName, pSize, mSize, (long)(exp * 1000), url, poolProps); 445 else 446 pool = new ConnectionPool(poolName, pSize, mSize, (long)(exp * 1000), url, user, pass); 447 448 try 450 { 451 DateFormat df = new SimpleDateFormat(dateformat); 452 pool.setDateFormat(df); 453 } 454 catch (Exception e) 455 { 456 log("Invalid dateformat string specified: " + dateformat); 457 } 458 459 if (logFile != null && !logFile.equals("")) 461 { 462 File f = new File(logFile); 463 if (f.exists() && f.isDirectory()) 464 log("Invalid logfile specified for pool " + poolName + " - specified file is a directory"); 465 else if (!f.exists() && !f.mkdirs()) 466 log("Invalid logfile specified for pool " + poolName + " - cannot create file " + f.getAbsolutePath()); 467 try { pool.setLog(new FileOutputStream(f, true)); } 468 catch (FileNotFoundException fnfe) 469 { 470 log(fnfe, "Invalid logfile specified for pool " + poolName); 471 pool.setLog(getLogStream()); 472 } 473 } 474 else 475 pool.setLog(getLogStream()); 476 477 if (poolDebug) 478 log("Enabling debug info on pool " + poolName); 479 pool.setDebug(poolDebug); 480 if (noCache) 481 log("Disabling caching on pool " + poolName); 482 pool.setCaching(!noCache); 483 if (async) 484 log("Enabling asynchronous destruction on pool " + poolName); 485 pool.setAsyncDestroy(async); 486 487 if (validator != null && !validator.equals("")) 489 { 490 try 491 { 492 Object o = Class.forName(validator).newInstance(); 493 if (o instanceof ConnectionValidator) 494 pool.setValidator((ConnectionValidator)o); 495 } 496 catch (Exception ex) 497 { 498 log("Unable to instantiate validator class for pool " + poolName + ": " + validator); 499 } 500 } 501 502 if (decoder != null && !decoder.equals("")) 504 { 505 try 506 { 507 Object o = Class.forName(decoder).newInstance(); 508 if (o instanceof PasswordDecoder) 509 pool.setPasswordDecoder((PasswordDecoder)o); 510 } 511 catch (Exception ex) 512 { 513 log("Unable to instantiate password decoder class for pool " + poolName + ": " + decoder); 514 } 515 } 516 517 synchronized(pools) { pools.put(poolName, pool); } 519 String info = "pool=" + pool.getPoolSize() + ",max=" + pool.getMaxSize() + ",expiry="; 520 info += pool.getExpiryTime() == 0 ? "none" : pool.getExpiryTime() + "ms"; 521 log("Initialized pool " + poolName + " (" + info + ")"); 522 523 if (iSize > 0) 525 pool.init(iSize); 526 } 527 } 528 } 529 530 537 public ConnectionPool getPool(String name) 538 { 539 if (released) 540 throw new RuntimeException ("Pool manager no longer valid for use"); 541 return (ConnectionPool)pools.get(name); 542 } 543 544 549 public ConnectionPool[] getPools() 550 { 551 synchronized(pools) 552 { 553 return (ConnectionPool[])pools.values().toArray(new ConnectionPool[0]); 554 } 555 } 556 557 564 public Connection getConnection(String name) throws SQLException 565 { 566 if (released) 567 throw new RuntimeException ("Pool manager no longer valid for use"); 568 569 ConnectionPool pool = (ConnectionPool)pools.get(name); 570 if (pool != null) 571 return pool.getConnection(); 572 return null; 573 } 574 575 584 public Connection getConnection(String name, long time) throws SQLException 585 { 586 if (released) 587 throw new RuntimeException ("Pool manager no longer valid for use"); 588 589 ConnectionPool pool = (ConnectionPool)pools.get(name); 590 if (pool != null) 591 return pool.getConnection(time); 592 return null; 593 } 594 595 599 public synchronized void release() 600 { 601 if (--clients > 0) 603 return; 604 released = true; 606 607 synchronized(pools) 608 { 609 for (Iterator it = pools.values().iterator(); it.hasNext();) 610 { 611 ConnectionPool pool = (ConnectionPool)it.next(); 612 pool.releaseForcibly(); 613 } 614 } 615 616 if (managers.size() == 1) 618 { 619 for (Iterator it = drivers.iterator(); it.hasNext();) 620 { 621 Driver driver = (Driver)it.next(); 622 try 623 { 624 DriverManager.deregisterDriver(driver); 625 log("Deregistered JDBC driver " + driver.getClass().getName()); 626 } 627 catch (SQLException sqle) 628 { 629 log(sqle, "Can't deregister JDBC driver: " + driver.getClass().getName()); 630 } 631 } 632 } 633 managers.remove(this.key); 635 636 super.close(); 638 } 639 640 643 public synchronized boolean isReleased() { return this.released; } 644 645 649 public synchronized void setValidator(ConnectionValidator cv) 650 { 651 synchronized(pools) 652 { 653 if (pools != null) 654 { 655 for (Iterator it = pools.values().iterator(); it.hasNext();) 656 ((ConnectionPool)it.next()).setValidator(cv); 657 } 658 } 659 } 660 661 665 public void setLog(OutputStream out) 666 { 667 super.setLog(out); 668 synchronized(pools) 670 { 671 if (pools != null) 672 { 673 for (Iterator it = pools.values().iterator(); it.hasNext();) 674 ((ConnectionPool)it.next()).setLog(out); 675 } 676 } 677 } 678 679 683 public void setLog(PrintStream ps) 684 { 685 super.setLog(ps); 686 synchronized(pools) 688 { 689 if (pools != null) 690 { 691 for (Iterator it = pools.values().iterator(); it.hasNext();) 692 ((ConnectionPool)it.next()).setLog(ps); 693 } 694 } 695 } 696 } | Popular Tags |