001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.dbcp2; 019 020import org.apache.commons.logging.Log; 021import org.apache.commons.logging.LogFactory; 022import org.apache.commons.pool2.impl.BaseObjectPoolConfig; 023import org.apache.commons.pool2.impl.GenericObjectPoolConfig; 024 025import java.io.ByteArrayInputStream; 026import java.nio.charset.StandardCharsets; 027import java.sql.Connection; 028import java.util.ArrayList; 029import java.util.Arrays; 030import java.util.Collection; 031import java.util.Enumeration; 032import java.util.Hashtable; 033import java.util.LinkedHashMap; 034import java.util.List; 035import java.util.Map; 036import java.util.Properties; 037import java.util.StringTokenizer; 038 039import javax.naming.Context; 040import javax.naming.Name; 041import javax.naming.RefAddr; 042import javax.naming.Reference; 043import javax.naming.spi.ObjectFactory; 044 045/** 046 * <p>JNDI object factory that creates an instance of 047 * <code>BasicDataSource</code> that has been configured based on the 048 * <code>RefAddr</code> values of the specified <code>Reference</code>, which 049 * must match the names and data types of the <code>BasicDataSource</code> bean 050 * properties with the following exceptions:</p> 051 * <ul> 052 * <li><code>connectionInitSqls</code> must be passed to this factory as a 053 * single String using semi-colon to delimit the statements whereas 054 * <code>BasicDataSource</code> requires a collection of Strings.</li> 055 * </ul> 056 * 057 * @author Craig R. McClanahan 058 * @author Dirk Verbeeck 059 * @version $Id: BasicDataSourceFactory.java 1660240 2015-02-16 22:45:31Z psteitz $ 060 * @since 2.0 061 */ 062public class BasicDataSourceFactory implements ObjectFactory { 063 064 private static final Log log = LogFactory.getLog(BasicDataSourceFactory.class); 065 066 private static final String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit"; 067 private static final String PROP_DEFAULTREADONLY = "defaultReadOnly"; 068 private static final String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation"; 069 private static final String PROP_DEFAULTCATALOG = "defaultCatalog"; 070 private static final String PROP_CACHESTATE ="cacheState"; 071 private static final String PROP_DRIVERCLASSNAME = "driverClassName"; 072 private static final String PROP_LIFO = "lifo"; 073 private static final String PROP_MAXTOTAL = "maxTotal"; 074 private static final String PROP_MAXIDLE = "maxIdle"; 075 private static final String PROP_MINIDLE = "minIdle"; 076 private static final String PROP_INITIALSIZE = "initialSize"; 077 private static final String PROP_MAXWAITMILLIS = "maxWaitMillis"; 078 private static final String PROP_TESTONCREATE = "testOnCreate"; 079 private static final String PROP_TESTONBORROW = "testOnBorrow"; 080 private static final String PROP_TESTONRETURN = "testOnReturn"; 081 private static final String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis"; 082 private static final String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun"; 083 private static final String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis"; 084 private static final String PROP_SOFTMINEVICTABLEIDLETIMEMILLIS = "softMinEvictableIdleTimeMillis"; 085 private static final String PROP_EVICTIONPOLICYCLASSNAME = "evictionPolicyClassName"; 086 private static final String PROP_TESTWHILEIDLE = "testWhileIdle"; 087 private static final String PROP_PASSWORD = "password"; 088 private static final String PROP_URL = "url"; 089 private static final String PROP_USERNAME = "username"; 090 private static final String PROP_VALIDATIONQUERY = "validationQuery"; 091 private static final String PROP_VALIDATIONQUERY_TIMEOUT = "validationQueryTimeout"; 092 private static final String PROP_JMX_NAME = "jmxName"; 093 094 /** 095 * The property name for connectionInitSqls. 096 * The associated value String must be of the form [query;]* 097 */ 098 private static final String PROP_CONNECTIONINITSQLS = "connectionInitSqls"; 099 private static final String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed"; 100 private static final String PROP_REMOVEABANDONEDONBORROW = "removeAbandonedOnBorrow"; 101 private static final String PROP_REMOVEABANDONEDONMAINTENANCE = "removeAbandonedOnMaintenance"; 102 private static final String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout"; 103 private static final String PROP_LOGABANDONED = "logAbandoned"; 104 private static final String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements"; 105 private static final String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements"; 106 private static final String PROP_CONNECTIONPROPERTIES = "connectionProperties"; 107 private static final String PROP_MAXCONNLIFETIMEMILLIS = "maxConnLifetimeMillis"; 108 private static final String PROP_LOGEXPIREDCONNECTIONS = "logExpiredConnections"; 109 private static final String PROP_ROLLBACK_ON_RETURN = "rollbackOnReturn"; 110 private static final String PROP_ENABLE_AUTOCOMMIT_ON_RETURN = "enableAutoCommitOnReturn"; 111 private static final String PROP_DEFAULT_QUERYTIMEOUT = "defaultQueryTimeout"; 112 private static final String PROP_FASTFAIL_VALIDATION = "fastFailValidation"; 113 114 /** 115 * Value string must be of the form [STATE_CODE,]* 116 */ 117 private static final String PROP_DISCONNECTION_SQL_CODES = "disconnectionSqlCodes"; 118 119 /* 120 * Block with obsolete properties from DBCP 1.x. 121 * Warn users that these are ignored and they should use the 2.x properties. 122 */ 123 private static final String NUPROP_MAXACTIVE = "maxActive"; 124 private static final String NUPROP_REMOVEABANDONED = "removeAbandoned"; 125 private static final String NUPROP_MAXWAIT = "maxWait"; 126 127 /* 128 * Block with properties expected in a DataSource 129 * This props will not be listed as ignored - we know that they may appear in Resource, 130 * and not listing them as ignored. 131 */ 132 private static final String SILENTPROP_FACTORY = "factory"; 133 private static final String SILENTPROP_SCOPE = "scope"; 134 private static final String SILENTPROP_SINGLETON = "singleton"; 135 private static final String SILENTPROP_AUTH = "auth"; 136 137 private static final String[] ALL_PROPERTIES = { 138 PROP_DEFAULTAUTOCOMMIT, 139 PROP_DEFAULTREADONLY, 140 PROP_DEFAULTTRANSACTIONISOLATION, 141 PROP_DEFAULTCATALOG, 142 PROP_CACHESTATE, 143 PROP_DRIVERCLASSNAME, 144 PROP_LIFO, 145 PROP_MAXTOTAL, 146 PROP_MAXIDLE, 147 PROP_MINIDLE, 148 PROP_INITIALSIZE, 149 PROP_MAXWAITMILLIS, 150 PROP_TESTONCREATE, 151 PROP_TESTONBORROW, 152 PROP_TESTONRETURN, 153 PROP_TIMEBETWEENEVICTIONRUNSMILLIS, 154 PROP_NUMTESTSPEREVICTIONRUN, 155 PROP_MINEVICTABLEIDLETIMEMILLIS, 156 PROP_SOFTMINEVICTABLEIDLETIMEMILLIS, 157 PROP_EVICTIONPOLICYCLASSNAME, 158 PROP_TESTWHILEIDLE, 159 PROP_PASSWORD, 160 PROP_URL, 161 PROP_USERNAME, 162 PROP_VALIDATIONQUERY, 163 PROP_VALIDATIONQUERY_TIMEOUT, 164 PROP_CONNECTIONINITSQLS, 165 PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED, 166 PROP_REMOVEABANDONEDONBORROW, 167 PROP_REMOVEABANDONEDONMAINTENANCE, 168 PROP_REMOVEABANDONEDTIMEOUT, 169 PROP_LOGABANDONED, 170 PROP_POOLPREPAREDSTATEMENTS, 171 PROP_MAXOPENPREPAREDSTATEMENTS, 172 PROP_CONNECTIONPROPERTIES, 173 PROP_MAXCONNLIFETIMEMILLIS, 174 PROP_LOGEXPIREDCONNECTIONS, 175 PROP_ROLLBACK_ON_RETURN, 176 PROP_ENABLE_AUTOCOMMIT_ON_RETURN, 177 PROP_DEFAULT_QUERYTIMEOUT, 178 PROP_FASTFAIL_VALIDATION, 179 PROP_DISCONNECTION_SQL_CODES 180 }; 181 182 /** 183 * Obsolete properties from DBCP 1.x. with warning strings suggesting 184 * new properties. LinkedHashMap will guarantee that properties will be listed 185 * to output in order of insertion into map. 186 */ 187 private static final Map<String, String> NUPROP_WARNTEXT = new LinkedHashMap<>(); 188 189 static { 190 NUPROP_WARNTEXT.put( 191 NUPROP_MAXACTIVE, 192 "Property " + NUPROP_MAXACTIVE + " is not used in DBCP2, use " + PROP_MAXTOTAL + " instead. " 193 + PROP_MAXTOTAL + " default value is " + GenericObjectPoolConfig.DEFAULT_MAX_TOTAL+"."); 194 NUPROP_WARNTEXT.put( 195 NUPROP_REMOVEABANDONED, 196 "Property " + NUPROP_REMOVEABANDONED + " is not used in DBCP2," 197 + " use one or both of " 198 + PROP_REMOVEABANDONEDONBORROW + " or " + PROP_REMOVEABANDONEDONMAINTENANCE + " instead. " 199 + "Both have default value set to false."); 200 NUPROP_WARNTEXT.put( 201 NUPROP_MAXWAIT, 202 "Property " + NUPROP_MAXWAIT + " is not used in DBCP2" 203 + " , use " + PROP_MAXWAITMILLIS + " instead. " 204 + PROP_MAXWAITMILLIS + " default value is " + BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS+"."); 205 } 206 207 /** 208 * Silent Properties. 209 * These properties will not be listed as ignored - we know that they may appear in JDBC Resource references, 210 * and we will not list them as ignored. 211 */ 212 private static final List<String> SILENT_PROPERTIES = new ArrayList<>(); 213 214 static { 215 SILENT_PROPERTIES.add(SILENTPROP_FACTORY); 216 SILENT_PROPERTIES.add(SILENTPROP_SCOPE); 217 SILENT_PROPERTIES.add(SILENTPROP_SINGLETON); 218 SILENT_PROPERTIES.add(SILENTPROP_AUTH); 219 220 } 221 222 // -------------------------------------------------- ObjectFactory Methods 223 224 /** 225 * <p>Create and return a new <code>BasicDataSource</code> instance. If no 226 * instance can be created, return <code>null</code> instead.</p> 227 * 228 * @param obj The possibly null object containing location or 229 * reference information that can be used in creating an object 230 * @param name The name of this object relative to <code>nameCtx</code> 231 * @param nameCtx The context relative to which the <code>name</code> 232 * parameter is specified, or <code>null</code> if <code>name</code> 233 * is relative to the default initial context 234 * @param environment The possibly null environment that is used in 235 * creating this object 236 * 237 * @exception Exception if an exception occurs creating the instance 238 */ 239 @Override 240 public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?,?> environment) 241 throws Exception { 242 243 // We only know how to deal with <code>javax.naming.Reference</code>s 244 // that specify a class name of "javax.sql.DataSource" 245 if (obj == null || !(obj instanceof Reference)) { 246 return null; 247 } 248 Reference ref = (Reference) obj; 249 if (!"javax.sql.DataSource".equals(ref.getClassName())) { 250 return null; 251 } 252 253 // Check property names and log warnings about obsolete and / or unknown properties 254 final List<String> warnings = new ArrayList<String>(); 255 final List<String> infoMessages = new ArrayList<String>(); 256 validatePropertyNames(ref, name, warnings, infoMessages); 257 for (String warning : warnings) { 258 log.warn(warning); 259 } 260 for (String infoMessage : infoMessages) { 261 log.info(infoMessage); 262 } 263 264 Properties properties = new Properties(); 265 for (String propertyName : ALL_PROPERTIES) { 266 RefAddr ra = ref.get(propertyName); 267 if (ra != null) { 268 String propertyValue = ra.getContent().toString(); 269 properties.setProperty(propertyName, propertyValue); 270 } 271 } 272 273 return createDataSource(properties); 274 } 275 276 /** 277 * Collects warnings and info messages. Warnings are generated when an obsolete 278 * property is set. Unknown properties generate info messages. 279 * 280 * @param ref Reference to check properties of 281 * @param name Name provided to getObject 282 * @param warnings container for warning messages 283 * @param infoMessages container for info messages 284 */ 285 private void validatePropertyNames(Reference ref, Name name, List<String> warnings, 286 List<String> infoMessages) { 287 final List<String> allPropsAsList = Arrays.asList(ALL_PROPERTIES); 288 final String nameString = name != null ? "Name = " + name.toString() + " " : ""; 289 if (NUPROP_WARNTEXT!=null && !NUPROP_WARNTEXT.keySet().isEmpty()) { 290 for (String propertyName : NUPROP_WARNTEXT.keySet()) { 291 final RefAddr ra = ref.get(propertyName); 292 if (ra != null && !allPropsAsList.contains(ra.getType())) { 293 final StringBuilder stringBuilder = new StringBuilder(nameString); 294 final String propertyValue = ra.getContent().toString(); 295 stringBuilder.append(NUPROP_WARNTEXT.get(propertyName)) 296 .append(" You have set value of \"") 297 .append(propertyValue) 298 .append("\" for \"") 299 .append(propertyName) 300 .append("\" property, which is being ignored."); 301 warnings.add(stringBuilder.toString()); 302 } 303 } 304 } 305 306 final Enumeration<RefAddr> allRefAddrs = ref.getAll(); 307 while (allRefAddrs.hasMoreElements()) { 308 final RefAddr ra = allRefAddrs.nextElement(); 309 final String propertyName = ra.getType(); 310 // If property name is not in the properties list, we haven't warned on it 311 // and it is not in the "silent" list, tell user we are ignoring it. 312 if (!(allPropsAsList.contains(propertyName) 313 || NUPROP_WARNTEXT.keySet().contains(propertyName) 314 || SILENT_PROPERTIES.contains(propertyName))) { 315 final String propertyValue = ra.getContent().toString(); 316 final StringBuilder stringBuilder = new StringBuilder(nameString); 317 stringBuilder.append("Ignoring unknown property: ") 318 .append("value of \"") 319 .append(propertyValue) 320 .append("\" for \"") 321 .append(propertyName) 322 .append("\" property"); 323 infoMessages.add(stringBuilder.toString()); 324 } 325 } 326 } 327 328 /** 329 * Creates and configures a {@link BasicDataSource} instance based on the 330 * given properties. 331 * 332 * @param properties the datasource configuration properties 333 * @throws Exception if an error occurs creating the data source 334 */ 335 public static BasicDataSource createDataSource(Properties properties) throws Exception { 336 BasicDataSource dataSource = new BasicDataSource(); 337 String value = null; 338 339 value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT); 340 if (value != null) { 341 dataSource.setDefaultAutoCommit(Boolean.valueOf(value)); 342 } 343 344 value = properties.getProperty(PROP_DEFAULTREADONLY); 345 if (value != null) { 346 dataSource.setDefaultReadOnly(Boolean.valueOf(value)); 347 } 348 349 value = properties.getProperty(PROP_DEFAULTTRANSACTIONISOLATION); 350 if (value != null) { 351 int level = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION; 352 if ("NONE".equalsIgnoreCase(value)) { 353 level = Connection.TRANSACTION_NONE; 354 } 355 else if ("READ_COMMITTED".equalsIgnoreCase(value)) { 356 level = Connection.TRANSACTION_READ_COMMITTED; 357 } 358 else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) { 359 level = Connection.TRANSACTION_READ_UNCOMMITTED; 360 } 361 else if ("REPEATABLE_READ".equalsIgnoreCase(value)) { 362 level = Connection.TRANSACTION_REPEATABLE_READ; 363 } 364 else if ("SERIALIZABLE".equalsIgnoreCase(value)) { 365 level = Connection.TRANSACTION_SERIALIZABLE; 366 } 367 else { 368 try { 369 level = Integer.parseInt(value); 370 } catch (NumberFormatException e) { 371 System.err.println("Could not parse defaultTransactionIsolation: " + value); 372 System.err.println("WARNING: defaultTransactionIsolation not set"); 373 System.err.println("using default value of database driver"); 374 level = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION; 375 } 376 } 377 dataSource.setDefaultTransactionIsolation(level); 378 } 379 380 value = properties.getProperty(PROP_DEFAULTCATALOG); 381 if (value != null) { 382 dataSource.setDefaultCatalog(value); 383 } 384 385 value = properties.getProperty(PROP_CACHESTATE); 386 if (value != null) { 387 dataSource.setCacheState(Boolean.valueOf(value).booleanValue()); 388 } 389 390 value = properties.getProperty(PROP_DRIVERCLASSNAME); 391 if (value != null) { 392 dataSource.setDriverClassName(value); 393 } 394 395 value = properties.getProperty(PROP_LIFO); 396 if (value != null) { 397 dataSource.setLifo(Boolean.valueOf(value).booleanValue()); 398 } 399 400 value = properties.getProperty(PROP_MAXTOTAL); 401 if (value != null) { 402 dataSource.setMaxTotal(Integer.parseInt(value)); 403 } 404 405 value = properties.getProperty(PROP_MAXIDLE); 406 if (value != null) { 407 dataSource.setMaxIdle(Integer.parseInt(value)); 408 } 409 410 value = properties.getProperty(PROP_MINIDLE); 411 if (value != null) { 412 dataSource.setMinIdle(Integer.parseInt(value)); 413 } 414 415 value = properties.getProperty(PROP_INITIALSIZE); 416 if (value != null) { 417 dataSource.setInitialSize(Integer.parseInt(value)); 418 } 419 420 value = properties.getProperty(PROP_MAXWAITMILLIS); 421 if (value != null) { 422 dataSource.setMaxWaitMillis(Long.parseLong(value)); 423 } 424 425 value = properties.getProperty(PROP_TESTONCREATE); 426 if (value != null) { 427 dataSource.setTestOnCreate(Boolean.valueOf(value).booleanValue()); 428 } 429 430 value = properties.getProperty(PROP_TESTONBORROW); 431 if (value != null) { 432 dataSource.setTestOnBorrow(Boolean.valueOf(value).booleanValue()); 433 } 434 435 value = properties.getProperty(PROP_TESTONRETURN); 436 if (value != null) { 437 dataSource.setTestOnReturn(Boolean.valueOf(value).booleanValue()); 438 } 439 440 value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS); 441 if (value != null) { 442 dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(value)); 443 } 444 445 value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN); 446 if (value != null) { 447 dataSource.setNumTestsPerEvictionRun(Integer.parseInt(value)); 448 } 449 450 value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS); 451 if (value != null) { 452 dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value)); 453 } 454 455 value = properties.getProperty(PROP_SOFTMINEVICTABLEIDLETIMEMILLIS); 456 if (value != null) { 457 dataSource.setSoftMinEvictableIdleTimeMillis(Long.parseLong(value)); 458 } 459 460 value = properties.getProperty(PROP_EVICTIONPOLICYCLASSNAME); 461 if (value != null) { 462 dataSource.setEvictionPolicyClassName(value); 463 } 464 465 value = properties.getProperty(PROP_TESTWHILEIDLE); 466 if (value != null) { 467 dataSource.setTestWhileIdle(Boolean.valueOf(value).booleanValue()); 468 } 469 470 value = properties.getProperty(PROP_PASSWORD); 471 if (value != null) { 472 dataSource.setPassword(value); 473 } 474 475 value = properties.getProperty(PROP_URL); 476 if (value != null) { 477 dataSource.setUrl(value); 478 } 479 480 value = properties.getProperty(PROP_USERNAME); 481 if (value != null) { 482 dataSource.setUsername(value); 483 } 484 485 value = properties.getProperty(PROP_VALIDATIONQUERY); 486 if (value != null) { 487 dataSource.setValidationQuery(value); 488 } 489 490 value = properties.getProperty(PROP_VALIDATIONQUERY_TIMEOUT); 491 if (value != null) { 492 dataSource.setValidationQueryTimeout(Integer.parseInt(value)); 493 } 494 495 value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED); 496 if (value != null) { 497 dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue()); 498 } 499 500 value = properties.getProperty(PROP_REMOVEABANDONEDONBORROW); 501 if (value != null) { 502 dataSource.setRemoveAbandonedOnBorrow(Boolean.valueOf(value).booleanValue()); 503 } 504 505 value = properties.getProperty(PROP_REMOVEABANDONEDONMAINTENANCE); 506 if (value != null) { 507 dataSource.setRemoveAbandonedOnMaintenance(Boolean.valueOf(value).booleanValue()); 508 } 509 510 value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT); 511 if (value != null) { 512 dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value)); 513 } 514 515 value = properties.getProperty(PROP_LOGABANDONED); 516 if (value != null) { 517 dataSource.setLogAbandoned(Boolean.valueOf(value).booleanValue()); 518 } 519 520 value = properties.getProperty(PROP_POOLPREPAREDSTATEMENTS); 521 if (value != null) { 522 dataSource.setPoolPreparedStatements(Boolean.valueOf(value).booleanValue()); 523 } 524 525 value = properties.getProperty(PROP_MAXOPENPREPAREDSTATEMENTS); 526 if (value != null) { 527 dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value)); 528 } 529 530 value = properties.getProperty(PROP_CONNECTIONINITSQLS); 531 if (value != null) { 532 dataSource.setConnectionInitSqls(parseList(value, ';')); 533 } 534 535 value = properties.getProperty(PROP_CONNECTIONPROPERTIES); 536 if (value != null) { 537 Properties p = getProperties(value); 538 Enumeration<?> e = p.propertyNames(); 539 while (e.hasMoreElements()) { 540 String propertyName = (String) e.nextElement(); 541 dataSource.addConnectionProperty(propertyName, p.getProperty(propertyName)); 542 } 543 } 544 545 value = properties.getProperty(PROP_MAXCONNLIFETIMEMILLIS); 546 if (value != null) { 547 dataSource.setMaxConnLifetimeMillis(Long.parseLong(value)); 548 } 549 550 value = properties.getProperty(PROP_LOGEXPIREDCONNECTIONS); 551 if (value != null) { 552 dataSource.setLogExpiredConnections(Boolean.valueOf(value).booleanValue()); 553 } 554 555 value = properties.getProperty(PROP_JMX_NAME); 556 if (value != null) { 557 dataSource.setJmxName(value); 558 } 559 560 value = properties.getProperty(PROP_ENABLE_AUTOCOMMIT_ON_RETURN); 561 if (value != null) { 562 dataSource.setEnableAutoCommitOnReturn(Boolean.valueOf(value).booleanValue()); 563 } 564 565 value = properties.getProperty(PROP_ROLLBACK_ON_RETURN); 566 if (value != null) { 567 dataSource.setRollbackOnReturn(Boolean.valueOf(value).booleanValue()); 568 } 569 570 value = properties.getProperty(PROP_DEFAULT_QUERYTIMEOUT); 571 if (value != null) { 572 dataSource.setDefaultQueryTimeout(Integer.valueOf(value)); 573 } 574 575 value = properties.getProperty(PROP_FASTFAIL_VALIDATION); 576 if (value != null) { 577 dataSource.setFastFailValidation(Boolean.valueOf(value).booleanValue()); 578 } 579 580 value = properties.getProperty(PROP_DISCONNECTION_SQL_CODES); 581 if (value != null) { 582 dataSource.setDisconnectionSqlCodes(parseList(value, ',')); 583 } 584 585 // DBCP-215 586 // Trick to make sure that initialSize connections are created 587 if (dataSource.getInitialSize() > 0) { 588 dataSource.getLogWriter(); 589 } 590 591 // Return the configured DataSource instance 592 return dataSource; 593 } 594 595 /** 596 * <p>Parse properties from the string. Format of the string must be [propertyName=property;]*<p> 597 * @param propText 598 * @return Properties 599 * @throws Exception 600 */ 601 private static Properties getProperties(String propText) throws Exception { 602 Properties p = new Properties(); 603 if (propText != null) { 604 p.load(new ByteArrayInputStream( 605 propText.replace(';', '\n').getBytes(StandardCharsets.ISO_8859_1))); 606 } 607 return p; 608 } 609 610 /** 611 * Parse list of property values from a delimited string 612 * @param value delimited list of values 613 * @param delimiter character used to separate values in the list 614 * @return String Collection of values 615 */ 616 private static Collection<String> parseList(String value, char delimiter) { 617 StringTokenizer tokenizer = new StringTokenizer(value, Character.toString(delimiter)); 618 Collection<String> tokens = 619 new ArrayList<String>(tokenizer.countTokens()); 620 while (tokenizer.hasMoreTokens()) { 621 tokens.add(tokenizer.nextToken()); 622 } 623 return tokens; 624 } 625}