1 20 21 package com.methodhead.persistable; 22 23 import java.io.IOException ; 24 import java.io.LineNumberReader ; 25 import java.io.Reader ; 26 27 import java.sql.Connection ; 28 import java.sql.ResultSet ; 29 import java.sql.SQLException ; 30 import java.sql.Statement ; 31 32 import java.util.HashMap ; 33 import java.util.Map ; 34 import java.util.Properties ; 35 36 import org.apache.commons.dbcp.AbandonedObjectPool; 37 import org.apache.commons.dbcp.AbandonedConfig; 38 import org.apache.commons.dbcp.ConnectionFactory; 39 import org.apache.commons.dbcp.DriverManagerConnectionFactory; 40 import org.apache.commons.dbcp.PoolableConnectionFactory; 41 import org.apache.commons.dbcp.PoolingDataSource; 42 import org.apache.commons.lang.exception.ExceptionUtils; 43 44 import org.apache.commons.pool.ObjectPool; 45 46 import org.apache.commons.pool.impl.GenericObjectPool; 47 48 import org.apache.log4j.Logger; 49 50 93 public class ConnectionSingleton { 94 95 97 private ConnectionSingleton() { 98 } 99 100 102 public static final String DBTYPE_MYSQL = "MYSQL"; 103 public static final String DBTYPE_PSQL = "PSQL"; 104 public static final String DBTYPE_SQLSERVER = "SQLSERVER"; 105 106 108 112 private static class CloseablePoolingDataSource 113 extends 114 PoolingDataSource { 115 116 119 public CloseablePoolingDataSource( 120 GenericObjectPool pool ) { 121 122 super( pool ); 123 pool_ = pool; 124 } 125 126 129 public void close() 130 throws 131 Exception { 132 pool_.close(); 133 } 134 135 private GenericObjectPool pool_ = null; 136 } 137 138 140 153 public static boolean init( 154 String name, Properties dbProps ) { 155 try { 156 if ( name == null ) 157 name = ""; 158 159 Object dataSource = connections_.get( name ); 160 161 if ( dataSource != null ) { 162 logger_.error( "Pool \"" + name + "\" is already initialized." ); 163 return false; 164 } 165 166 if ( dbProps.getProperty( "validQuery" ) == null ) 170 dbProps.setProperty( "validQuery", "SELECT 1" ); 171 if ( dbProps.getProperty( "evictionPeriodMillis" ) == null ) 172 dbProps.setProperty( "evictionPeriodMillis", "3600000" ); 173 if ( dbProps.getProperty( "maxActive" ) == null ) 174 dbProps.setProperty( "maxActive", "8" ); 175 if ( dbProps.getProperty( "maxWaitMillis" ) == null ) 176 dbProps.setProperty( "maxWaitMillis", "2000" ); 177 if ( dbProps.getProperty( "logAbandoned" ) == null ) 178 dbProps.setProperty( "logAbandoned", "false" ); 179 if ( dbProps.getProperty( "abandonedTimeout" ) == null ) 180 dbProps.setProperty( "abandonedTimeout", "300" ); 181 182 dbProps.setProperty( 186 "driver", dbProps.getProperty( "driver" ).trim() ); 187 dbProps.setProperty( 188 "uri", dbProps.getProperty( "uri" ).trim() ); 189 dbProps.setProperty( 190 "user", dbProps.getProperty( "user" ).trim() ); 191 dbProps.setProperty( 192 "password", dbProps.getProperty( "password" ).trim() ); 193 dbProps.setProperty( 194 "validQuery", dbProps.getProperty( "validQuery" ).trim() ); 195 dbProps.setProperty( 196 "evictionPeriodMillis", 197 dbProps.getProperty( "evictionPeriodMillis" ).trim() ); 198 dbProps.setProperty( 199 "maxActive", dbProps.getProperty( "maxActive" ).trim() ); 200 dbProps.setProperty( 201 "maxWaitMillis", dbProps.getProperty( "maxWaitMillis" ).trim() ); 202 dbProps.setProperty( 203 "logAbandoned", dbProps.getProperty( "logAbandoned" ).trim() ); 204 dbProps.setProperty( 205 "abandonedTimeout", dbProps.getProperty( "abandonedTimeout" ).trim() ); 206 207 Class.forName( dbProps.getProperty( "driver" ).trim() ); 208 209 GenericObjectPool connectionPool = null; 213 214 if ( "true".equals( dbProps.getProperty( "logAbandoned" ) ) ) { 215 216 AbandonedConfig abandonedConfig = new AbandonedConfig(); 217 abandonedConfig.setLogAbandoned( true ); 218 abandonedConfig.setRemoveAbandoned( true ); 219 abandonedConfig.setRemoveAbandonedTimeout( Integer.parseInt( dbProps.getProperty( "abandonedTimeout" ) ) ); 220 221 connectionPool = new AbandonedObjectPool( null, abandonedConfig ); 222 } 223 else { 224 connectionPool = new GenericObjectPool( null ); 225 } 226 227 connectionPool.setMaxActive( Integer.parseInt( dbProps.getProperty( "maxActive" ) ) ); 231 connectionPool.setWhenExhaustedAction( GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 232 connectionPool.setMaxWait( Integer.parseInt( dbProps.getProperty( "maxWaitMillis" ) ) ); 233 connectionPool.setTestWhileIdle( true ); 234 connectionPool.setTimeBetweenEvictionRunsMillis( Integer.parseInt( dbProps.getProperty( "evictionPeriodMillis" ) ) ); 235 236 DriverManagerConnectionFactory connectionFactory = 237 new DriverManagerConnectionFactory( 238 dbProps.getProperty( "uri" ), dbProps ); 239 240 PoolableConnectionFactory poolableConnectionFactory = 241 new PoolableConnectionFactory( 242 connectionFactory, connectionPool, null, dbProps.getProperty( "validQuery" ), false, true ); 249 dataSource = new CloseablePoolingDataSource(connectionPool); 250 251 connections_.put( name, dataSource ); 255 256 return true; 257 } 258 catch ( Exception e ) { 259 logger_.error( 260 "Unexpected exception while initing pool \"" + name + "\": " + e ); 261 return false; 262 } 263 } 264 265 269 public static boolean init( 270 Properties dbProps ) { 271 return init( null, dbProps ); 272 } 273 274 283 public static Connection getConnection( 284 String name ) 285 throws 286 SQLException { 287 288 if ( name == null ) 289 name = ""; 290 291 CloseablePoolingDataSource dataSource = 292 ( CloseablePoolingDataSource )connections_.get( name ); 293 294 if ( dataSource == null ) 295 throw new SQLException ( 296 "Pool \"" + name + "\" has not been initialized yet." ); 297 298 return dataSource.getConnection(); 299 } 300 301 305 public static Connection getConnection() 306 throws 307 SQLException { 308 return getConnection( null ); 309 } 310 311 315 public static void release( 316 String name ) 317 throws 318 SQLException { 319 320 if ( name == null ) 321 name = ""; 322 323 CloseablePoolingDataSource dataSource = 324 ( CloseablePoolingDataSource )connections_.get( name ); 325 326 if ( dataSource == null ) 327 throw new SQLException ( 328 "Pool \"" + name + "\" has not been initialized yet." ); 329 330 try { 331 dataSource.close(); 332 } 333 catch ( Exception e ) { 334 throw new SQLException ( 335 "Unexpected exception while releasing pool \"" + name + "\":" + e ); 336 } 337 338 connections_.remove( name ); 339 } 340 341 345 public static void release() 346 throws 347 SQLException { 348 349 release( null ); 350 } 351 352 358 public static void close( 359 ResultSet rs ) { 360 361 try { 362 if ( ( rs != null ) && ( rs.getStatement() != null ) && ( rs.getStatement().getConnection() != null ) ) { 363 rs.getStatement().getConnection().close(); 364 } 365 } 366 catch ( SQLException e ) { 367 logger_.error( "Closing connection. " + ExceptionUtils.getStackTrace( e ) ); 368 } 369 } 370 371 381 public static ResultSet runQuery( 382 String name, 383 String sql ) 384 throws 385 SQLException { 386 387 Connection conn = null; 388 try { 389 logger_.debug( sql ); 390 391 conn = ConnectionSingleton.getConnection( name ); 392 if ( conn == null ) 393 throw 394 new SQLException ( 395 "Pool has not been initialized yet: \"" + name + "\"" ); 396 397 ResultSet rs = conn.prepareStatement( sql ).executeQuery(); 398 399 if ( rs == null ) { 400 logger_.error( "Couldn't execute sql \"" + sql + "\" and database connection may still be open." ); 401 } 402 403 return rs; 404 } 405 catch ( SQLException e ) { 406 if ( conn != null ) 407 conn.close(); 408 throw new SQLException ( 409 e.toString() + " while executing \"" + sql + "\"" ); 410 } 411 } 412 413 417 public static ResultSet runQuery( 418 String sql ) 419 throws 420 SQLException { 421 return runQuery( null, sql ); 422 } 423 424 428 public static int runUpdate( 429 String name, 430 String sql ) 431 throws 432 SQLException { 433 Connection conn = null; 434 try { 435 logger_.debug( sql ); 436 437 conn = ConnectionSingleton.getConnection( name ); 438 if ( conn == null ) 439 throw 440 new SQLException ( 441 "Pool has not been initialized yet: \"" + name + "\"" ); 442 443 int i = conn.prepareStatement( sql ).executeUpdate(); 444 conn.close(); 445 return i; 446 } 447 catch ( SQLException e ) { 448 if ( conn != null ) 449 conn.close(); 450 throw new SQLException ( 451 e.toString() + " while executing \"" + sql + "\"" ); 452 } 453 } 454 455 460 public static int runUpdate( 461 String sql ) 462 throws 463 SQLException { 464 return runUpdate( null, sql ); 465 } 466 467 497 public static void runBatchUpdate( 498 String name, 499 Reader reader ) 500 throws 501 IOException , 502 SQLException { 503 504 LineNumberReader lineReader = 505 new LineNumberReader ( reader ); 506 507 String line = null; 508 StringBuffer buf = new StringBuffer (); 509 510 while ( true ) { 511 512 buf.setLength( 0 ); 516 while ( ( line = lineReader.readLine() ) != null ) { 517 if ( line.startsWith( "--" ) ) 518 continue; 519 520 if ( line.indexOf( "--" ) != -1 ) 521 line = line.substring( 0, line.indexOf( "--" ) ); 522 523 if ( line.indexOf( ";" ) != -1 ) 524 buf.append( line.substring( 0, line.indexOf( ";" ) ) ); 525 else 526 buf.append( line ); 527 528 buf.append( " " ); 529 530 if ( line.indexOf( ";" ) != -1 ) 531 break; 532 } 533 534 String statement = buf.toString().trim(); 538 539 if ( statement.length() > 0 ) 543 runUpdate( name, buf.toString() ); 544 545 if ( line == null ) 546 break; 547 } 548 } 549 550 554 public static void runBatchUpdate( 555 Reader reader ) 556 throws 557 IOException , 558 SQLException { 559 560 runBatchUpdate( null, reader ); 561 } 562 563 569 public static String getDatabaseType( 570 String name ) { 571 572 Connection conn = null; 573 try { 574 conn = getConnection( name ); 575 String productName = conn.getMetaData().getDatabaseProductName(); 576 conn.close(); 577 578 if ( "MySQL".equals( productName ) ) 579 return DBTYPE_MYSQL; 580 581 if ( "PostgreSQL".equals( productName ) ) 582 return DBTYPE_PSQL; 583 584 if ( "Microsoft SQL Server".equals( productName ) ) 585 return DBTYPE_SQLSERVER; 586 587 throw new PersistableException( 588 "Unexpected database type \"" + productName + "\"." ); 589 } 590 catch ( SQLException e ) { 591 throw new RuntimeException ( 592 "Unexpected SQLException: " + ExceptionUtils.getStackTrace( e ) ); 593 } 594 } 595 596 602 public static String getDatabaseType() { 603 return getDatabaseType( null ); 604 } 605 606 607 609 611 protected static Map connections_ = new HashMap (); 612 613 private static Logger logger_ = Logger.getLogger( ConnectionSingleton.class ); 614 } 615 | Popular Tags |