View Javadoc
1 package org.apache.torque.pool; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Turbine" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * "Apache Turbine", nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>. 55 */ 56 57 import java.io.PrintWriter; 58 import java.io.Serializable; 59 import java.sql.Connection; 60 import java.sql.SQLException; 61 import java.util.HashMap; 62 import java.util.Hashtable; 63 import java.util.Map; 64 import java.util.Properties; 65 import javax.naming.BinaryRefAddr; 66 import javax.naming.Context; 67 import javax.naming.InitialContext; 68 import javax.naming.Name; 69 import javax.naming.NamingException; 70 import javax.naming.RefAddr; 71 import javax.naming.Reference; 72 import javax.naming.Referenceable; 73 import javax.naming.StringRefAddr; 74 import javax.naming.spi.ObjectFactory; 75 import javax.sql.ConnectionPoolDataSource; 76 import javax.sql.DataSource; 77 import org.apache.commons.lang.SerializationUtils; 78 79 /*** 80 * Torque's default connection pool DataSource 81 * 82 * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a> 83 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> 84 * @version $Id: TorqueClassicDataSource.java,v 1.11 2003/08/18 21:48:11 mpoeschl Exp $ 85 * @deprecated as of version 3.1 86 */ 87 public class TorqueClassicDataSource 88 implements DataSource, Referenceable, Serializable, ObjectFactory 89 { 90 /*** Pools keyed by username. */ 91 private static Map pools = new HashMap(); 92 93 /*** Counter used to create an internal unique name od the Data Source */ 94 private static int cpdsCounter; 95 96 /*** DataSource Name used to find the ConnectionPoolDataSource */ 97 private String dataSourceName; 98 99 /*** Description */ 100 private String description; 101 102 /*** Login TimeOut in seconds */ 103 private int loginTimeout; 104 105 /*** Pool Data Source that is used to fetch connections */ 106 private ConnectionPoolDataSource cpds; 107 108 /*** Log stream */ 109 private PrintWriter logWriter; 110 111 /*** Environment that may be used to set up a jndi initial context. */ 112 private Properties jndiEnvironment; 113 114 /*** Maximum Number of Connections cached in this Data Source */ 115 private int defaultMaxConnections; 116 117 /*** 118 * Maximum Number of Connections for a specified User in this Data 119 * Source 120 */ 121 private Properties perUserMaxConnections; 122 123 /*** Maximum lifetime of a database connection */ 124 private int maxExpiryTime; 125 126 /*** 127 * time to wait when initiating a connection 128 * for the database to respond 129 */ 130 private int connectionWaitTimeout; 131 132 /*** Interval (in seconds) that the monitor thread reports the pool state */ 133 private int logInterval; 134 135 /*** Do connections from this pool are auto-committing? */ 136 private boolean defaultAutoCommit; 137 138 /*** Are connections from this pool read-only? */ 139 private boolean defaultReadOnly; 140 141 /*** 142 * Default no-arg constructor for Serialization 143 */ 144 public TorqueClassicDataSource() 145 { 146 defaultAutoCommit = true; 147 } 148 149 // Properties 150 151 /*** 152 * Get the number of database connections to cache per user. 153 * This value is used for any username which is not specified 154 * in perUserMaxConnections. The default is 1. 155 * 156 * @return value of maxConnections. 157 */ 158 public int getDefaultMaxConnections() 159 { 160 return defaultMaxConnections; 161 } 162 163 /*** 164 * Set the number of database connections to cache per user. 165 * This value is used for any username which is not specified 166 * in perUserMaxConnections. The default is 1. 167 * 168 * @param v Value to assign to maxConnections. 169 */ 170 public void setDefaultMaxConnections(int v) 171 { 172 this.defaultMaxConnections = v; 173 } 174 175 /*** 176 * Get the number of database connections to cache per user. The keys 177 * are usernames and the value is the maximum connections. Any username 178 * specified here will override the value of defaultMaxConnections. 179 * 180 * @return value of perUserMaxConnections. 181 */ 182 public Properties getPerUserMaxConnections() 183 { 184 return perUserMaxConnections; 185 } 186 187 /*** 188 * Set the number of database connections to cache per user. The keys 189 * are usernames and the value is the maximum connections. Any username 190 * specified here will override the value of defaultMaxConnections. 191 * 192 * @param v Value to assign to perUserMaxConnections. 193 */ 194 public void setPerUserMaxConnections(Properties v) 195 { 196 this.perUserMaxConnections = v; 197 } 198 199 /*** 200 * Get the amount of time (in seconds) that database connections 201 * will be cached. The default is 3600 (1 hour). 202 * 203 * @return value of expiryTime. 204 */ 205 public int getMaxExpiryTime() 206 { 207 return maxExpiryTime; 208 } 209 210 /*** 211 * Set the amount of time (in seconds) that database connections 212 * will be cached. The default is 3600 (1 hour). 213 * 214 * @param v Value to assign to expiryTime. 215 */ 216 public void setMaxExpiryTime(int v) 217 { 218 this.maxExpiryTime = v; 219 } 220 221 /*** 222 * Get the amount of time (in seconds) a connection request will 223 * have to wait before a time out occurs and an error is thrown. 224 * The default is 10 seconds. 225 * 226 * @return value of connectionWaitTimeout. 227 */ 228 public int getConnectionWaitTimeout() 229 { 230 return connectionWaitTimeout; 231 } 232 233 /*** 234 * Eet the amount of time (in seconds) a connection request will 235 * have to wait before a time out occurs and an error is thrown. 236 * The default is 10 seconds. 237 * 238 * @param v Value to assign to connectionWaitTimeout. 239 */ 240 public void setConnectionWaitTimeout(int v) 241 { 242 this.connectionWaitTimeout = v; 243 } 244 245 /*** 246 * Get the interval (in seconds) between which the ConnectionPool logs 247 * the status of it's Connections. Default is 0 which indicates no 248 * logging. 249 * 250 * @return value of logInterval. 251 */ 252 public int getLogInterval() 253 { 254 return logInterval; 255 } 256 257 /*** 258 * Set the interval (in seconds) between which the ConnectionPool logs 259 * the status of it's Connections. Default is 0 which indicates no 260 * logging. 261 * 262 * @param v Value to assign to logInterval. 263 */ 264 public void setLogInterval(int v) 265 { 266 this.logInterval = v; 267 } 268 269 /*** 270 * Get the value of defaultAutoCommit, which defines the state of 271 * connections handed out from this pool. The value can be changed 272 * on the Connection using Connection.setAutoCommit(boolean). 273 * The default is true. 274 * 275 * @return value of defaultAutoCommit. 276 */ 277 public boolean isDefaultAutoCommit() 278 { 279 return defaultAutoCommit; 280 } 281 282 /*** 283 * Set the value of defaultAutoCommit, which defines the state of 284 * connections handed out from this pool. The value can be changed 285 * on the Connection using Connection.setAutoCommit(boolean). 286 * The default is true. 287 * 288 * @param v Value to assign to defaultAutoCommit. 289 */ 290 public void setDefaultAutoCommit(boolean v) 291 { 292 this.defaultAutoCommit = v; 293 } 294 295 /*** 296 * Get the value of defaultReadOnly, which defines the state of 297 * connections handed out from this pool. The value can be changed 298 * on the Connection using Connection.setReadOnly(boolean). 299 * The default is false. 300 * 301 * @return value of defaultReadOnly. 302 */ 303 public boolean isDefaultReadOnly() 304 { 305 return defaultReadOnly; 306 } 307 308 /*** 309 * Set the value of defaultReadOnly, which defines the state of 310 * connections handed out from this pool. The value can be changed 311 * on the Connection using Connection.setReadOnly(boolean). 312 * The default is false. 313 * 314 * @param v Value to assign to defaultReadOnly. 315 */ 316 public void setDefaultReadOnly(boolean v) 317 { 318 this.defaultReadOnly = v; 319 } 320 321 /*** 322 * Get the name of the ConnectionPoolDataSource which backs this pool. 323 * This name is used to look up the datasource from a jndi service 324 * provider. 325 * 326 * @return value of dataSourceName. 327 */ 328 public String getDataSourceName() 329 { 330 return dataSourceName; 331 } 332 333 /*** 334 * Set the name of the ConnectionPoolDataSource which backs this pool. 335 * This name is used to look up the datasource from a jndi service 336 * provider. 337 * 338 * @param v Value to assign to dataSourceName. 339 */ 340 public void setDataSourceName(String v) 341 { 342 if (getConnectionPoolDataSource() != null) 343 { 344 throw new IllegalStateException("connectionPoolDataSource property" 345 + " already has a value. Both dataSourceName and " 346 + "connectionPoolDataSource properties cannot be set."); 347 } 348 349 this.dataSourceName = v; 350 } 351 352 353 /*** 354 * Get the description. This property is defined by jdbc as for use with 355 * GUI (or other) tools that might deploy the datasource. It serves no 356 * internal purpose. 357 * 358 * @return value of description. 359 */ 360 public String getDescription() 361 { 362 return description; 363 } 364 365 /*** 366 * Set the description. This property is defined by jdbc as for use with 367 * GUI (or other) tools that might deploy the datasource. It serves no 368 * internal purpose. 369 * 370 * @param v Value to assign to description. 371 */ 372 public void setDescription(String v) 373 { 374 this.description = v; 375 } 376 377 378 /*** 379 * Get the value of jndiEnvironment which is used when instantiating 380 * a jndi InitialContext. This InitialContext is used to locate the 381 * backend ConnectionPoolDataSource. 382 * 383 * @param key environment key 384 * @return value of jndiEnvironment. 385 */ 386 public String getJndiEnvironment(String key) 387 { 388 String value = null; 389 if (jndiEnvironment != null) 390 { 391 value = jndiEnvironment.getProperty(key); 392 } 393 return value; 394 } 395 396 /*** 397 * Set the value of jndiEnvironment which is used when instantiating 398 * a jndi InitialContext. This InitialContext is used to locate the 399 * backend ConnectionPoolDataSource. 400 * 401 * @param key environment key 402 * @param value Value to assign to jndiEnvironment. 403 */ 404 public void setJndiEnvironment(String key, String value) 405 { 406 if (jndiEnvironment == null) 407 { 408 jndiEnvironment = new Properties(); 409 } 410 jndiEnvironment.setProperty(key, value); 411 } 412 413 414 /*** 415 * Get the value of connectionPoolDataSource. This method will return 416 * null, if the backing datasource is being accessed via jndi. 417 * 418 * @return value of connectionPoolDataSource. 419 */ 420 public ConnectionPoolDataSource getConnectionPoolDataSource() 421 { 422 return cpds; 423 } 424 425 /*** 426 * Set the backend ConnectionPoolDataSource. This property should not be 427 * set if using jndi to access the datasource. 428 * 429 * @param v Value to assign to connectionPoolDataSource. 430 */ 431 public void setConnectionPoolDataSource(ConnectionPoolDataSource v) 432 { 433 if (v == null) 434 { 435 throw new IllegalArgumentException( 436 "Null argument value is not allowed."); 437 } 438 if (getDataSourceName() != null) 439 { 440 throw new IllegalStateException("dataSourceName property" 441 + " already has a value. Both dataSourceName and " 442 + "connectionPoolDataSource properties cannot be set."); 443 } 444 this.cpds = v; 445 446 // set the dataSourceName to a unique value 447 dataSourceName = v.hashCode() + " internal cpds name " + cpdsCounter++; 448 } 449 450 /*** 451 * Attempt to establish a database connection. 452 * 453 * @return A database connection. 454 * @throws SQLException 455 */ 456 public Connection getConnection() throws SQLException 457 { 458 return getConnection(null, null); 459 } 460 461 /*** 462 * Attempt to establish a database connection. 463 * 464 * @param username The name of the database user. 465 * @param password The password of the database user. 466 * @return A database connection. 467 * @throws SQLException 468 */ 469 public synchronized Connection getConnection(String username, 470 String password) 471 throws SQLException 472 { 473 String key = getKey(username); 474 ConnectionPool pool = (ConnectionPool) pools.get(key); 475 if (pool == null) 476 { 477 try 478 { 479 registerPool(username, password); 480 pool = (ConnectionPool) pools.get(key); 481 } 482 catch (Exception e) 483 { 484 throw new SQLException(e.getMessage()); 485 } 486 } 487 488 Connection con = pool.getConnection(username, password).getConnection(); 489 con.setAutoCommit(defaultAutoCommit); 490 con.setReadOnly(defaultReadOnly); 491 return con; 492 } 493 494 /*** 495 * 496 * @param suffix 497 * @return 498 */ 499 private String getKey(String suffix) 500 { 501 String key = getDataSourceName(); 502 if (key == null) 503 { 504 throw new IllegalStateException("Attempted to use DataSource " 505 + "without a backend ConnectionPoolDataSource defined."); 506 } 507 508 if (suffix != null) 509 { 510 key += suffix; 511 } 512 return key; 513 } 514 515 /*** 516 * 517 * @param username The name of the database user. 518 * @param password The password of the database user. 519 * @throws javax.naming.NamingException 520 */ 521 synchronized private void registerPool(String username, String password) 522 throws javax.naming.NamingException 523 { 524 String key = getKey(username); 525 if (!pools.containsKey(key)) 526 { 527 ConnectionPoolDataSource cpds = this.cpds; 528 if (cpds == null) 529 { 530 Context ctx = null; 531 if (jndiEnvironment == null) 532 { 533 ctx = new InitialContext(); 534 } 535 else 536 { 537 ctx = new InitialContext(jndiEnvironment); 538 } 539 cpds = (ConnectionPoolDataSource) ctx.lookup(dataSourceName); 540 } 541 542 int maxConnections = getDefaultMaxConnections(); 543 if (username != null) 544 { 545 String userMaxCon = 546 (String) getPerUserMaxConnections().get(username); 547 if (userMaxCon != null) 548 { 549 maxConnections = Integer.parseInt(userMaxCon); 550 } 551 } 552 553 ConnectionPool pool = new ConnectionPool(cpds, username, password, 554 maxConnections, 555 getMaxExpiryTime(), 556 getConnectionWaitTimeout(), 557 getLogInterval()); 558 559 // avoid ConcurrentModificationException 560 Map newPools = new HashMap(pools); 561 newPools.put(key, pool); 562 pools = newPools; 563 } 564 } 565 566 /*** 567 * Gets the maximum time in seconds that this data source can wait 568 * while attempting to connect to a database. 569 * 570 * @return the login timeout 571 */ 572 public int getLoginTimeout() 573 { 574 return loginTimeout; 575 } 576 577 /*** 578 * Get the log writer for this data source. 579 * 580 * @return the log writer 581 * @deprecated Use correct debugging and logging code from Log4j 582 */ 583 public PrintWriter getLogWriter() 584 { 585 if (logWriter == null) 586 { 587 logWriter = new PrintWriter(System.out); 588 } 589 return logWriter; 590 } 591 592 /*** 593 * Sets the maximum time in seconds that this data source will wait 594 * while attempting to connect to a database. NOT USED. 595 * 596 * @param seconds the login timeout 597 */ 598 public void setLoginTimeout(int seconds) 599 { 600 loginTimeout = seconds; 601 } 602 603 /*** 604 * Set the log writer for this data source. 605 * 606 * @param out the log writer to use 607 * @deprecated Use correct debugging and logging code from Log4j 608 */ 609 public void setLogWriter(java.io.PrintWriter out) 610 { 611 logWriter = out; 612 } 613 614 /*** 615 * <CODE>Referenceable</CODE> implementation. 616 * 617 * @return a reference 618 * @throws NamingException 619 */ 620 public Reference getReference() throws NamingException 621 { 622 String factory = getClass().getName(); 623 624 Reference ref = new Reference(getClass().getName(), factory, null); 625 626 ref.add(new StringRefAddr("defaultMaxConnections", 627 String.valueOf(getDefaultMaxConnections()))); 628 ref.add(new StringRefAddr("maxExpiryTime", 629 String.valueOf(getMaxExpiryTime()))); 630 ref.add(new StringRefAddr("connectionWaitTimeout", 631 String.valueOf(getConnectionWaitTimeout()))); 632 ref.add(new StringRefAddr("logInterval", 633 String.valueOf(getLogInterval()))); 634 ref.add(new StringRefAddr("dataSourceName", getDataSourceName())); 635 ref.add(new StringRefAddr("description", getDescription())); 636 637 byte[] serJndiEnv = null; 638 // BinaryRefAddr does not allow null byte[]. 639 if (jndiEnvironment != null) 640 { 641 serJndiEnv = SerializationUtils.serialize(jndiEnvironment); 642 ref.add(new BinaryRefAddr("jndiEnvironment", serJndiEnv)); 643 } 644 645 byte[] serPUMC = null; 646 // BinaryRefAddr does not allow null byte[]. 647 if (getPerUserMaxConnections() != null) 648 { 649 serPUMC = SerializationUtils.serialize(getPerUserMaxConnections()); 650 ref.add(new BinaryRefAddr("perUserMaxConnections", serPUMC)); 651 } 652 653 return ref; 654 } 655 656 /*** 657 * implements ObjectFactory to create an instance of this class 658 * 659 * @param refObj 660 * @param name 661 * @param context 662 * @param env 663 * @return an instance of this class 664 * @throws Exception 665 */ 666 public Object getObjectInstance(Object refObj, Name name, 667 Context context, Hashtable env) 668 throws Exception 669 { 670 Reference ref = (Reference) refObj; 671 672 if (ref.getClassName().equals(getClass().getName())) 673 { 674 setDefaultMaxConnections(Integer.parseInt( 675 (String) ref.get("defaultMaxConnections").getContent())); 676 setMaxExpiryTime(Integer.parseInt( 677 (String) ref.get("maxExpiryTime").getContent())); 678 setConnectionWaitTimeout(Integer.parseInt( 679 (String) ref.get("connectionWaitTimeout").getContent())); 680 setLogInterval(Integer.parseInt( 681 (String) ref.get("logInterval").getContent())); 682 setDataSourceName((String) ref.get("dataSourceName").getContent()); 683 setDescription((String) ref.get("description").getContent()); 684 685 RefAddr refAddr = ref.get("jndiEnvironment"); 686 if (refAddr != null) 687 { 688 byte[] serialized = (byte[]) refAddr.getContent(); 689 jndiEnvironment = (Properties) 690 SerializationUtils.deserialize(serialized); 691 } 692 693 refAddr = ref.get("perUserMaxConnections"); 694 if (refAddr != null) 695 { 696 byte[] serialized = (byte[]) refAddr.getContent(); 697 setPerUserMaxConnections( 698 (Properties) SerializationUtils.deserialize(serialized)); 699 } 700 701 return this; 702 } 703 else 704 { 705 // We can't create an instance of the reference 706 return null; 707 } 708 } 709 }

This page was automatically generated by Maven