1 56 package org.objectstyle.cayenne.conf; 57 58 import java.io.IOException ; 59 import java.io.InputStream ; 60 import java.sql.Connection ; 61 import java.util.Properties ; 62 63 import javax.sql.DataSource ; 64 65 import org.apache.commons.dbcp.ConnectionFactory; 66 import org.apache.commons.dbcp.DriverManagerConnectionFactory; 67 import org.apache.commons.dbcp.PoolableConnectionFactory; 68 import org.apache.commons.dbcp.PoolingDataSource; 69 import org.apache.commons.pool.KeyedObjectPoolFactory; 70 import org.apache.commons.pool.ObjectPool; 71 import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory; 72 import org.apache.commons.pool.impl.GenericObjectPool; 73 import org.apache.log4j.Level; 74 import org.apache.log4j.Logger; 75 import org.objectstyle.cayenne.ConfigurationException; 76 77 238 public class DBCPDataSourceFactory implements DataSourceFactory { 239 240 private static final Logger logger = Logger.getLogger(DBCPDataSourceFactory.class); 241 242 245 private static final String SUFFIX = ".properties"; 246 247 252 public static final String PROPERTY_PREFIX = "cayenne.dbcp."; 253 254 259 public static final String PS_PROPERTY_PREFIX = PROPERTY_PREFIX + "ps."; 260 261 protected Configuration parentConfiguration; 262 263 public void initializeWithParentConfiguration(Configuration parentConfiguration) { 264 this.parentConfiguration = parentConfiguration; 265 } 266 267 275 public DataSource getDataSource(String location) throws Exception { 276 return getDataSource(location, Level.DEBUG); 277 } 278 279 286 public DataSource getDataSource(String location, Level logLevel) throws Exception { 287 288 if (!location.endsWith(SUFFIX)) { 289 location = location.concat(SUFFIX); 290 } 291 292 logger.log(logLevel, "Loading DBCP properties from " + location); 293 294 Properties properties = loadProperties(location); 295 logger.log(logLevel, "Loaded DBCP properties: " + properties); 296 297 loadDriverClass(properties, logLevel); 298 299 ConnectionFactory factory = createConnectionFactory(properties); 301 KeyedObjectPoolFactory statementPool = createStatementPool(properties); 302 303 GenericObjectPool.Config config = createPoolConfig(properties); 304 305 String validationQuery = stringProperty(properties, "validationQuery"); 307 boolean defaultReadOnly = booleanProperty(properties, "defaultReadOnly", false); 308 boolean defaultAutoCommit = booleanProperty( 309 properties, 310 "defaultAutoCommit", 311 false); 312 int defaultTransactionIsolation = defaultTransactionIsolation( 313 properties, 314 "defaultTransactionIsolation", 315 Connection.TRANSACTION_SERIALIZABLE); 316 String defaultCatalog = stringProperty(properties, "defaultCatalog"); 317 318 ObjectPool connectionPool = new GenericObjectPool(null, config); 323 new PoolableConnectionFactory( 324 factory, 325 connectionPool, 326 statementPool, 327 validationQuery, 328 defaultReadOnly ? Boolean.TRUE : Boolean.FALSE, 329 defaultAutoCommit, 330 defaultTransactionIsolation, 331 defaultCatalog, 332 null); 333 334 PoolingDataSource dataSource = new PoolingDataSource(connectionPool); 335 dataSource.setAccessToUnderlyingConnectionAllowed(booleanProperty( 336 properties, 337 "accessToUnderlyingConnectionAllowed", 338 false)); 339 340 return dataSource; 341 } 342 343 346 void loadDriverClass(Properties properties, Level level) throws Exception { 347 String driver = stringProperty(properties, "driverClassName"); 348 logger.log(level, "loading JDBC driver class: " + driver); 349 350 if (driver == null) { 351 throw new NullPointerException ("No value for required property: " 352 + PROPERTY_PREFIX 353 + "driverClassName"); 354 } 355 Class.forName(driver); 356 } 357 358 KeyedObjectPoolFactory createStatementPool(Properties properties) throws Exception { 359 360 if (!booleanProperty(properties, "poolPreparedStatements", false)) { 361 return null; 362 } 363 364 370 int maxActive = intProperty( 371 properties, 372 "ps.maxActive", 373 GenericObjectPool.DEFAULT_MAX_ACTIVE); 374 byte whenExhaustedAction = whenExhaustedAction( 375 properties, 376 "ps.whenExhaustedAction", 377 GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION); 378 379 long maxWait = longProperty( 380 properties, 381 "ps.maxWait", 382 GenericObjectPool.DEFAULT_MAX_WAIT); 383 384 int maxIdle = intProperty( 385 properties, 386 "ps.maxIdle", 387 GenericObjectPool.DEFAULT_MAX_IDLE); 388 389 int maxTotal = intProperty(properties, "ps.maxTotal", 1); 390 391 boolean testOnBorrow = booleanProperty( 392 properties, 393 "ps.testOnBorrow", 394 GenericObjectPool.DEFAULT_TEST_ON_BORROW); 395 boolean testOnReturn = booleanProperty( 396 properties, 397 "ps.testOnReturn", 398 GenericObjectPool.DEFAULT_TEST_ON_RETURN); 399 400 long timeBetweenEvictionRunsMillis = longProperty( 401 properties, 402 "ps.timeBetweenEvictionRunsMillis", 403 GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS); 404 int numTestsPerEvictionRun = intProperty( 405 properties, 406 "ps.numTestsPerEvictionRun", 407 GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN); 408 409 long minEvictableIdleTimeMillis = longProperty( 410 properties, 411 "ps.minEvictableIdleTimeMillis", 412 GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS); 413 414 boolean testWhileIdle = booleanProperty( 415 properties, 416 "ps.testWhileIdle", 417 GenericObjectPool.DEFAULT_TEST_WHILE_IDLE); 418 419 return new GenericKeyedObjectPoolFactory( 420 null, 421 maxActive, 422 whenExhaustedAction, 423 maxWait, 424 maxIdle, 425 maxTotal, 426 testOnBorrow, 427 testOnReturn, 428 timeBetweenEvictionRunsMillis, 429 numTestsPerEvictionRun, 430 minEvictableIdleTimeMillis, 431 testWhileIdle); 432 } 433 434 ConnectionFactory createConnectionFactory(Properties properties) { 435 String url = stringProperty(properties, "url"); 436 String userName = stringProperty(properties, "username"); 437 String password = stringProperty(properties, "password"); 438 439 if (url == null) { 441 throw new NullPointerException ("No value for required property: " 442 + PROPERTY_PREFIX 443 + "url"); 444 } 445 446 return new DriverManagerConnectionFactory(url, userName, password); 447 } 448 449 GenericObjectPool.Config createPoolConfig(Properties properties) throws Exception { 450 GenericObjectPool.Config config = new GenericObjectPool.Config(); 451 452 config.maxIdle = intProperty( 453 properties, 454 "maxIdle", 455 GenericObjectPool.DEFAULT_MAX_IDLE); 456 config.minIdle = intProperty( 457 properties, 458 "minIdle", 459 GenericObjectPool.DEFAULT_MIN_IDLE); 460 config.maxActive = intProperty( 461 properties, 462 "maxActive", 463 GenericObjectPool.DEFAULT_MAX_ACTIVE); 464 config.maxWait = longProperty( 465 properties, 466 "maxWait", 467 GenericObjectPool.DEFAULT_MAX_WAIT); 468 469 config.testOnBorrow = booleanProperty( 470 properties, 471 "testOnBorrow", 472 GenericObjectPool.DEFAULT_TEST_ON_BORROW); 473 config.testOnReturn = booleanProperty( 474 properties, 475 "testOnReturn", 476 GenericObjectPool.DEFAULT_TEST_ON_RETURN); 477 config.testWhileIdle = booleanProperty( 478 properties, 479 "testWhileIdle", 480 GenericObjectPool.DEFAULT_TEST_WHILE_IDLE); 481 482 config.timeBetweenEvictionRunsMillis = longProperty( 483 properties, 484 "timeBetweenEvictionRunsMillis", 485 GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS); 486 config.numTestsPerEvictionRun = intProperty( 487 properties, 488 "numTestsPerEvictionRun", 489 GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN); 490 config.minEvictableIdleTimeMillis = longProperty( 491 properties, 492 "minEvictableIdleTimeMillis", 493 GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS); 494 495 config.whenExhaustedAction = whenExhaustedAction( 496 properties, 497 "whenExhaustedAction", 498 GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION); 499 500 return config; 501 } 502 503 Properties loadProperties(String location) throws IOException { 504 505 Properties properties = new Properties (); 506 InputStream in = getInputStream(location); 507 if (in == null) { 508 throw new ConfigurationException("DBCP properties file not found: " 509 + location); 510 } 511 512 try { 513 properties.load(in); 514 } 515 finally { 516 try { 517 in.close(); 518 } 519 catch (IOException ignore) { 520 } 521 } 522 523 return properties; 524 } 525 526 int defaultTransactionIsolation( 527 Properties properties, 528 String property, 529 int defaultValue) { 530 531 String value = stringProperty(properties, property); 532 533 if (value == null) { 534 return defaultValue; 535 } 536 537 try { 539 return Integer.parseInt(value); 540 } 541 catch (NumberFormatException nfex) { 542 try { 544 return Connection .class.getField(value).getInt(null); 545 } 546 catch (Throwable th) { 547 throw new ConfigurationException( 548 "Invalid 'defaultTransactionIsolation': " + value); 549 } 550 } 551 } 552 553 byte whenExhaustedAction(Properties properties, String property, byte defaultValue) 554 throws Exception { 555 556 String value = stringProperty(properties, property); 557 558 if (value == null) { 559 return defaultValue; 560 } 561 562 try { 564 return Byte.parseByte(value); 565 } 566 catch (NumberFormatException nfex) { 567 try { 569 return GenericObjectPool.class.getField(value).getByte(null); 570 } 571 catch (Throwable th) { 572 throw new ConfigurationException("Invalid 'whenExhaustedAction': " 573 + value); 574 } 575 } 576 } 577 578 String stringProperty(Properties properties, String property) { 579 return properties.getProperty(PROPERTY_PREFIX + property); 580 } 581 582 boolean booleanProperty(Properties properties, String property, boolean defaultValue) { 583 String value = stringProperty(properties, property); 584 return (value != null) ? "true".equalsIgnoreCase(stringProperty( 585 properties, 586 property)) : defaultValue; 587 } 588 589 int intProperty(Properties properties, String property, int defaultValue) { 590 String value = stringProperty(properties, property); 591 592 try { 593 return (value != null) ? Integer.parseInt(value) : defaultValue; 594 } 595 catch (NumberFormatException nfex) { 596 return defaultValue; 597 } 598 } 599 600 long longProperty(Properties properties, String property, long defaultValue) { 601 String value = stringProperty(properties, property); 602 try { 603 return (value != null) ? Long.parseLong(value) : defaultValue; 604 } 605 catch (NumberFormatException nfex) { 606 return defaultValue; 607 } 608 } 609 610 byte byteProperty(Properties properties, String property, byte defaultValue) { 611 String value = stringProperty(properties, property); 612 try { 613 return (value != null) ? Byte.parseByte(value) : defaultValue; 614 } 615 catch (NumberFormatException nfex) { 616 return defaultValue; 617 } 618 } 619 620 623 InputStream getInputStream(String location) { 624 if (this.parentConfiguration == null) { 625 throw new ConfigurationException( 626 "No parent Configuration set - cannot continue."); 627 } 628 629 return this.parentConfiguration.getResourceLocator().findResourceStream(location); 630 } 631 } | Popular Tags |