You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by hu...@apache.org on 2003/05/09 12:15:39 UTC

cvs commit: jakarta-struts/contrib/struts-legacy/src/java/org/apache/struts/legacy GenericDataSource.java GenericConnection.java

husted      2003/05/09 03:15:39

  Added:       contrib/struts-legacy/src/java/org/apache/struts/legacy
                        GenericDataSource.java GenericConnection.java
  Log:
  + "Whiteboard" struts-legacy package to host the original GenericDataSource.
  
  Revision  Changes    Path
  1.1                  jakarta-struts/contrib/struts-legacy/src/java/org/apache/struts/legacy/GenericDataSource.java
  
  Index: GenericDataSource.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-struts/contrib/struts-legacy/src/java/org/apache/struts/legacy/GenericDataSource.java,v 1.1 2003/05/09 10:15:38 husted Exp $
   * $Revision: 1.1 $
   * $Date: 2003/05/09 10:15:38 $
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Struts", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  
  package org.apache.struts.legacy;
  
  
  import java.io.PrintWriter;
  import java.sql.Connection;
  import java.sql.Driver;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.sql.Statement;
  import java.util.LinkedList;
  import java.util.Properties;
  import javax.sql.DataSource;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  
  /**
   * <p>Generic data source implementation of the <code>DataSource</code>
   * interface.  <b>WARNING</b> - This implementation does not know how to
   * provide connections with different username/password combinations.
   * Calling this version of the implementation using the
   * getConnection(username,password) signature will throw an exception.</p>
   *
   * <p>The following properties are supported by the standard
   * <code>GenericDataSource</code> implementation:</p>
   * <table>
   * <tr>
   *   <th width="15%">Property</th>
   *   <th width="85%">Description</th>
   * </tr>
   * <tr>
   *   <td align="center">autoCommit</td>
   *   <td>Set to <code>true</code> if you want the connections returned to you
   *       by calling <code>getConnection()</code> to be configured in
   *       "auto-commit after every statement" mode.  The default value is
   *       <code>true</code>, to conform to JDBC standard conventions.</td>
   * </tr>
   * <tr>
   *   <td align="center">description</td>
   *   <td>A short textual description of this data source.  This property is
   *       required by the <code>javax.sql.DataSource</code> interface, but is
   *       not used within this implementation.</td>
   * </tr>
   * <tr>
   *   <td align="center">driverClass</td>
   *   <td>The fully qualified class name of the JDBC driver to be utilized for
   *       the connections created by this data source.  Consult the
   *       documentation for your JDBC driver to identify the value to be
   *       configured for this property.</td>
   * </tr>
   * <tr>
   *   <td align="center">maxCount</td>
   *   <td>The maximum number of JDBC connections that will be created by this
   *       data source.  This value must be greater than or equal to the value
   *       specified for the <code>minCount</count> property.</td>
   * </tr>
   * <tr>
   *   <td align="center">minCount</td>
   *   <td>The minimum number of JDBC connections to establish when this data
   *       source is first opened.  This value must be less than or equal to the
   *       value specified for the <code>maxCount</code> property.</td>
   * </tr>
   * <tr>
   *   <td align="center">password</td>
   *   <td>The database password used to establish the connections created by
   *       this connection pool, in conjunction with the username specified in
   *       the <code>user</code> property.</td>
   * </tr>
   * <tr>
   *   <td align="center">pingCommand</td>
   *   <td>A non-query SQL command that, if specified, will be executed before
   *       a connection is returned by a call to <code>getConnection()</code>.
   *       If any SQLException is thrown by the execution of this statement,
   *       it is assumed that this connection is stale and it will be discarded.
   *       Because this happens on every connection allocation, you should ensure
   *       that the statement executes very quickly.</td>
   * </tr>
   * <tr>
   *   <td align="center">pingQuery</td>
   *   <td>A query SQL command (i.e. a SELECT) that, if specified, will be
   *       executed before a connection is returned by a call to
   *       <code>getConnection()</code>.  If any SQLException is thrown by the
   *       execution of this query (or by the subsequent processing of the
   *       entire returned <code>ResultSet</code>), it is assumed that this
   *       connection is stale and it will be discarded.  Because this happens
   *       on every connection allocation, you should ensure that the
   *       statement executes very quickly.</td>
   * </tr>
   * <tr>
   *   <td align="center">readOnly</td>
   *   <td>Set to <code>true</code> if you want the connections returned to you
   *       by calling <code>getConnection()</code> to be configured for read only
   *       operations.  This can result in more efficient database access,
   *       because the database will know it does not need to retain undo logs
   *       for rolling back the transaction.  The default value is
   *       <code>false</code>.</td>
   * </tr>
   * <tr>
   *   <td align="center">url</td>
   *   <td>The connection URL to be passed to our JDBC driver when establishing
   *       a new connection.  The value specified typically starts with
   *       <code>jdbc:</code>, and includes a reference to the host (and,
   *       optionally, the port number) at which the database server is listening
   *       for connections, plus the name of the database to be opened.  Consult
   *       the documentation for your JDBC driver to identify the value to be
   *       configured for this property.</td>
   * </tr>
   * <tr>
   *   <td align="center">user</td>
   *   <td>The database username used to establish the connections created by
   *       this connection pool, in conjunction with the password specified in
   *       the <code>password</code> property.</td>
   * </tr>
   * </table>
   *
   * <p>In addition, you can add to the set of <code>Properties</code> passed to
   * the JDBC driver by calling <code>addProperty()</code>.</p>
   * <p>
   * This class was originally maintained in the core Struts util package [revision 1.11].
   * </p>
   *
   * @author Craig R. McClanahan
   * @author Ted Husted
   * @version $Revision: 1.1 $ $Date: 2003/05/09 10:15:38 $
   */
  
  public class GenericDataSource implements DataSource {
  
      // ----------------------------------------------------------- Util Methods
  
      /**
       * Return the <code>Class</code> object for the specified fully qualified
       * class name, from this web application's class loader.
       * <p>
       * See util.RequestUtils.applicationClass for maintained original.
       *
       * @param className Fully qualified class name to be loaded
       * @return Class object
       * @exception ClassNotFoundException if the class cannot be found
       */
      private static Class applicationClass(String className) throws ClassNotFoundException {
  
          // Look up the class loader to be used
          ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
          if (classLoader == null) {
              classLoader = GenericDataSource.class.getClassLoader();
          }
  
          // Attempt to load the specified class
          return (classLoader.loadClass(className));
  
      }
  
      /**
       * Return a new instance of the specified fully qualified class name,
       * after loading the class from this web application's class loader.
       * The specified class <strong>MUST</strong> have a public zero-arguments
       * constructor.
       * <p>
       * See util.RequestUtils.applicationClass for maintained original.
       *
       * @param className Fully qualified class name to use
       * @return new instance of class
       * @exception ClassNotFoundException if the class cannot be found
       * @exception IllegalAccessException if the class or its constructor
       *  is not accessible
       * @exception InstantiationException if this class represents an
       *  abstract class, an interface, an array class, a primitive type,
       *  or void
       * @exception InstantiationException if this class has no
       *  zero-arguments constructor
       */
      private static Object applicationInstance(String className)
          throws ClassNotFoundException, IllegalAccessException, InstantiationException {
  
          return (applicationClass(className).newInstance());
  
      }
  
  
      // ----------------------------------------------------- Instance Constants
  
  
      private static final String SQLEXCEPTION_GETCONNECTION =
       "getConnection(String username, String password)  Method not supported. Use getConnection() instead.";
  
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * Has this data source been closed?
       */
      protected boolean closed = false;
  
  
      /**
       * The list of Connections (wrapped in our associated wrapper class) that
       * have been created but are not currently in use.
       */
      protected LinkedList connections = new LinkedList();
  
  
      /**
       * The JDBC driver that we use as a connection factory.
       */
      protected Driver driver = null;
  
  
      /**
       * Commons Logging instance.
       */
      protected Log log = LogFactory.getLog(this.getClass());
  
  
      /**
       * The login timeout for this data source.
       */
      protected int loginTimeout = 0;
  
  
      /**
       * The log writer for this data source.
       */
      protected PrintWriter logWriter = null;
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Add a generic property to the list of connection properties to be used.
       *
       * @param name Name of the generic property
       * @param value Corresponding generic property value
       */
      public void addProperty(String name, String value) {
          properties.put(name, value);
      }
  
  
      /**
       * The number of connections that have been created by this data source.
       */
      protected int activeCount = 0;
  
      public int getActiveCount() {
          return (this.activeCount);
      }
  
  
      /**
       * The default auto-commit state for newly created connections.
       */
      protected boolean autoCommit = true;
  
      public boolean getAutoCommit() {
          return (this.autoCommit);
      }
  
      public void setAutoCommit(boolean autoCommit) {
          this.autoCommit = autoCommit;
      }
  
  
      /**
       * The debugging detail level for this data source.
       */
      protected int debug = 0;
  
      public int getDebug() {
          return (this.debug);
      }
  
      public void setDebug(int debug) {
          this.debug = debug;
      }
  
  
      /**
       * The description of this data source.
       */
      protected String description = null;
  
      public String getDescription() {
          return (this.description);
      }
  
      public void setDescription(String description) {
          this.description = description;
      }
  
  
      /**
       * The Java class name of the JDBC driver to use.
       */
      protected String driverClass = null;
  
      public String getDriverClass() {
          return (this.driverClass);
      }
  
      public void setDriverClass(String driverClass) {
          this.driverClass = driverClass;
      }
  
  
      /**
       * The maximum number of connections to be created.
       */
      protected int maxCount = 2;
  
      public int getMaxCount() {
          return (this.maxCount);
      }
  
      public void setMaxCount(int maxCount) {
          this.maxCount = maxCount;
      }
  
  
      /**
       * The minimum number of connections to be created.
       */
      protected int minCount = 1;
  
      public int getMinCount() {
          return (this.minCount);
      }
  
      public void setMinCount(int minCount) {
          this.minCount = minCount;
      }
  
  
      /**
       * The database password for use in establishing a connection.
       */
      protected String password = null;
  
      public String getPassword() {
          return (this.password);
      }
  
      public void setPassword(String password) {
          this.password = password;
          addProperty("password", this.password);
      }
  
  
  
      /**
       * The non-query SQL command used to ping an allocated connection.
       */
      protected String pingCommand = null;
  
      public String getPingCommand() {
          return (this.pingCommand);
      }
  
      public void setPingCommand(String pingCommand) {
          this.pingCommand = pingCommand;
      }
  
  
      /**
       * The query SQL command used to ping an allocated connection.
       */
      protected String pingQuery = null;
  
      public String getPingQuery() {
          return (this.pingQuery);
      }
  
      public void setPingQuery(String pingQuery) {
          this.pingQuery = pingQuery;
      }
  
  
      /**
       * The connection properties for use in establishing connections.
       */
      protected Properties properties = new Properties();
  
  
      /**
       * The default read-only state for newly created connections.
       */
      protected boolean readOnly = false;
  
      public boolean getReadOnly() {
          return (this.readOnly);
      }
  
      public void setReadOnly(boolean readOnly) {
          this.readOnly = readOnly;
      }
  
  
      /**
       * The JDBC URL for the database connection to be opened.
       */
      protected String url = null;
  
      public String getUrl() {
          return (this.url);
      }
  
      public void setUrl(String url) {
          this.url = url;
      }
  
  
      /**
       * The number of connections created by this data source that are
       * currently in use.
       */
      protected int useCount = 0;
  
      public int getUseCount() {
          return (this.useCount);
      }
  
  
      /**
       * The database username for use in establishing a connection.
       */
      protected String user = null;
  
      public String getUser() {
          return (this.user);
      }
  
      public void setUser(String user) {
          this.user = user;
          addProperty("user", this.user);
      }
  
  
      // ----------------------------------------------------- DataSource Methods
  
  
      /**
       * Attempt to establish a database connection.
       *
       * @exception SQLException if a database access error occurs
       */
      public Connection getConnection() throws SQLException {
  
          int seconds = 0;
          if (log.isInfoEnabled()) {
              log.info("  getConnection()");
          }
  
          // Validate the opened status of this data source
          if (closed) {
              throw new SQLException("getConnection:  Data source is closed");
          }
          if (driver == null) {
              open();
          }
  
          while (true) {
  
              // Have we timed out yet?
              if (log.isInfoEnabled()) {
                  log.info("   Check for timeout, activeCount=" + activeCount +
                      ", useCount=" + useCount);
              }
              if ((loginTimeout > 0) && (seconds >= loginTimeout)) {
                  break;
              }
  
              // Return an existing connection from the pool if there is one
              synchronized (connections) {
                  if (!connections.isEmpty()) {
  
                      // Allocate the first available connection
                      GenericConnection connection =
                          (GenericConnection) connections.removeFirst();
                      if (log.isInfoEnabled()) {
                          log.info("   Found available connection");
                      }
  
                      // Make sure this connection is not stale
                      connection.setClosed(false);
                      try {
                          ping(connection);
                      } catch (SQLException e) {
                          log.warn("   Connection stale, releasing");
                          try {
                              connection.getConnection().close();
                          } catch (SQLException f) {
                              ;
                          }
                          activeCount--;
                          continue;
                      }
  
                      // unclose the connection's wrapper and return it
                      useCount++;
                      if (log.isInfoEnabled()) {
                          log.info("   Return allocated connection, activeCount=" +
                                   activeCount + ", useCount=" + useCount);
                      }
  
                      return(connection);
  
                  }
              }
  
              // Create a new connection if we are not yet at the maximum
              if (activeCount < maxCount) {
                  Connection connection = createConnection();
                  if (connection != null) {
                      try {
                          ping(connection);
                      } catch (SQLException e) {
                          throw e;
                      }
                      useCount++;
                      if (log.isInfoEnabled()) {
                          log.info("   Return new connection, activeCount=" +
                                   activeCount + ", useCount=" + useCount);
                      }
  
                      return (connection);
                  }
              }
  
              // Wait for an existing connection to be returned
              if (log.isInfoEnabled()) {
                  log.info("   Sleep until next test");
              }
              try {
                  Thread.sleep(1000);
                  seconds++;
              } catch (InterruptedException e) {
                  ;
              }
  
          }
  
          // We have timed out awaiting an available connection
          if (log.isInfoEnabled()) {
              log.info("   Timeout awaiting connection");
          }
          throw new SQLException
              ("getConnection: Timeout awaiting connection");
  
      }
  
  
      /**
       * Attempt to establish a database connection.  <b>WARNING</b> - The
       * specified username and password are not supported by this
       * implementation.
       *
       * @param username Database username for this connection
       * @param password Database password for this connection
       *
       * @exception SQLException if a database access error occurs
       */
      public Connection getConnection(String username, String password)
          throws SQLException {
  
          throw new SQLException(SQLEXCEPTION_GETCONNECTION); // Not implemented
  
      }
  
  
      /**
       * Return the login timeout for this data source.
       *
       * @exception SQLException if a database access error occurs
       */
      public int getLoginTimeout() throws SQLException {
  
          return (this.loginTimeout);
  
      }
  
  
  
      /**
       * Return the log writer for this data source.
       *
       * @exception SQLException if a database access error occurs
       */
      public PrintWriter getLogWriter() throws SQLException {
  
          return (this.logWriter);
  
      }
  
  
      /**
       * Set the login timeout for this data source.
       *
       * @param loginTimeout The new login timeout
       *
       * @exception SQLException if a database access error occurs
       */
      public void setLoginTimeout(int loginTimeout) throws SQLException {
  
          this.loginTimeout = loginTimeout;
  
      }
  
  
      /**
       * Set the log writer for this data source.
       *
       * @param logWriter The new log writer
       *
       * @exception SQLException if a database access error occurs
       */
      public void setLogWriter(PrintWriter logWriter) throws SQLException {
  
          this.logWriter = logWriter;
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Close all connections that have been created by this data source.
       *
       * @exception SQLException if a database access error occurs
       */
      public void close() throws SQLException {
  
          if (closed)
              throw new SQLException("close:  Data Source already closed");
          if (log.isDebugEnabled()) {
              log.debug(" close()");
          }
  
          // Shut down all active connections
          while (activeCount > 0) {
              GenericConnection conn = (GenericConnection) getConnection();
              conn.getConnection().close();
              activeCount--;
          }
  
          // Mark this data source as having been closed and release our driver
          closed = true;
          driver = null;
  
      }
  
  
      /**
       * Open the initial connections that are appropriate for this data source.
       *
       * @exception SQLException if a database access error occurs
       */
      public void open() throws SQLException {
  
          // Have we already been opened?
          if (driver != null)
              return;
          if (log.isDebugEnabled()) {
              log.debug(" open()");
          }
  
          // Instantiate our database driver
          try {
              driver = (Driver) applicationInstance(driverClass);
          } catch (Throwable t) {
              throw new SQLException("open: " + t);
          }
  
          // Create the initial minimum number of required connections
          synchronized (connections) {
              for (int i = 0; i < minCount; i++) {
                  connections.addLast(createConnection());
              }
          }
  
          closed = false;
  
      }
  
  
      /**
       * Return a string representation of this component.
       */
      public String toString() {
  
          StringBuffer sb = new StringBuffer("GenericDataSource[");
          sb.append("activeCount=");
          sb.append(activeCount);
          sb.append(", autoCommit=");
          sb.append(autoCommit);
          sb.append(", closed=");
          sb.append(closed);
          if (description != null) {
              sb.append(", description=");
              sb.append(description);
          }
          sb.append(", driverClass=");
          sb.append(driverClass);
          sb.append(", loginTimeout=");
          sb.append(loginTimeout);
          sb.append(", maxCount=");
          sb.append(maxCount);
          sb.append(", minCount=");
          sb.append(minCount);
          sb.append(", password=");
          sb.append(password);
          sb.append(", readOnly=");
          sb.append(readOnly);
          sb.append(", url=");
          sb.append(url);
          sb.append(", useCount=");
          sb.append(useCount);
          sb.append(", user=");
          sb.append(user);
          sb.append("]");
          return (sb.toString());
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Create, configure, and return a new JDBC Connection that has been
       * wrapped in our corresponding wrapper.
       *
       * @exception SQLException if a database access error occurs
       */
      protected synchronized Connection createConnection() throws SQLException {
  
          if (activeCount < maxCount) {
              if (log.isInfoEnabled()) {
                  log.info("   createConnection()");
              }
              Connection conn = driver.connect(url, properties);
              activeCount++;
              return (new GenericConnection(this, conn, autoCommit, readOnly));
          }
  
          log.error("   createConnection() returning null");
  
          return (null);
  
      }
  
  
      /**
       * Log the specified message to our log writer, if we have one.
       *
       * @param message The message to be logged
       */
      protected void log(String message) {
  
          if (logWriter != null) {
              logWriter.print("GenericDataSource[");
              logWriter.print(description);
              logWriter.print("]: ");
              logWriter.println(message);
          }
  
      }
  
  
      /**
       * Log the specified message and exception to our log writer, if we
       * have one.
       *
       * @param message The message to be logged
       * @param throwable The exception to be logged
       */
      protected void log(String message, Throwable throwable) {
  
          if (logWriter != null) {
              logWriter.print("GenericDataSource[");
              logWriter.print(description);
              logWriter.print("]: ");
              logWriter.println(message);
              throwable.printStackTrace(logWriter);
          }
  
      }
  
  
      /**
       * Perform any configured <code>pingCommand</code> and/or
       * <code>pingQuery</code> on the specified connection, returning any
       * SQLException that is encountered along the way.
       *
       * @param conn The connection to be pinged
       */
      protected void ping(Connection conn) throws SQLException {
  
          if (pingCommand != null) {
  
              if (log.isDebugEnabled()) {
                  log.debug("    ping(" + pingCommand + ")");
              }
  
              Statement stmt = conn.createStatement();
              try {
                  stmt.execute(pingCommand);
                  stmt.close();
              } catch (SQLException e) {
                  log.warn("ping failed:  " + e.getMessage(), e);
  
                  try {
                      if (stmt != null) {
                          stmt.close();
                      }
                  } catch (SQLException f) {
                      ;
                  }
                  throw e;
              }
  
          }
  
          if (pingQuery != null) {
  
              if (log.isDebugEnabled()) {
                  log.debug("    ping(" + pingQuery + ")");
              }
  
              ResultSet rs = null;
              Statement stmt = conn.createStatement();
              try {
                  rs = stmt.executeQuery(pingQuery);
                  while (rs.next()) {
                      ;
                  }
                  rs.close();
                  stmt.close();
              } catch (SQLException e) {
                  log.warn("ping failed: " + e.getMessage(), e);
  
                  try {
                      if (rs != null)
                          rs.close();
                  } catch (SQLException f) {
                      ;
                  }
                  try {
                      if (stmt != null)
                          stmt.close();
                  } catch (SQLException f) {
                      ;
                  }
                  throw e;
              }
  
          }
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      /**
       * Return this connection to the available connection pool.
       *
       * @param conn The connection being returned
       */
      void returnConnection(GenericConnection conn) {
  
          if (log.isInfoEnabled()) {
              log.info("  releaseConnection(), activeCount=" + activeCount +
                  ", useCount=" + (useCount - 1));
          }
  
          synchronized (connections) {
              connections.addLast(conn);
              useCount--;
          }
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-struts/contrib/struts-legacy/src/java/org/apache/struts/legacy/GenericConnection.java
  
  Index: GenericConnection.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-struts/contrib/struts-legacy/src/java/org/apache/struts/legacy/GenericConnection.java,v 1.1 2003/05/09 10:15:38 husted Exp $
   * $Revision: 1.1 $
   * $Date: 2003/05/09 10:15:38 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Struts", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  
  package org.apache.struts.legacy;
  
  
  import java.sql.CallableStatement;
  import java.sql.Connection;
  import java.sql.DatabaseMetaData;
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import java.sql.SQLWarning;
  import java.sql.Statement;
  import java.sql.Savepoint;
  import java.util.Map;
  import javax.sql.DataSource;
  
  
  /**
   * Generic wrapper implementation of a <strong>Connection</strong> that
   * works with <code>GenericDataSource</code> to wrap connections for any
   * JDBC driver.
   * <p>
   * This version of the source MUST be compiled under Java 1.4 or later.
   * </p>
   * <p>
   * This class was originally maintained in the core Struts util package.
   * </p>
   *
   * @author Craig R. McClanahan
   * @author Ted Husted
   * @version $Revision: 1.1 $ $Date: 2003/05/09 10:15:38 $
   */
  
  public class GenericConnection implements Connection {
  
      // ---------------------------------------------- since 1.4 - not supported
      // To compile under 1.3, this block of signatures can be commented out.
  
      public void setHoldability(int holdability) throws SQLException {
          throw new UnsupportedOperationException();
      }
  
      public int getHoldability() throws SQLException{
          throw new UnsupportedOperationException();
      }
  
      public Savepoint setSavepoint() throws SQLException {
          throw new UnsupportedOperationException();
      }
  
      public Savepoint setSavepoint(String name) throws SQLException {
          throw new UnsupportedOperationException();
      }
  
      public void rollback(Savepoint savepoint) throws SQLException {
          throw new UnsupportedOperationException();
      }
  
      public void releaseSavepoint(Savepoint savepoint) throws SQLException {
          throw new UnsupportedOperationException();
      }
  
      public Statement createStatement(int resultSetType, int resultSetConcurrency,
  			      int resultSetHoldability) throws SQLException {
          throw new UnsupportedOperationException();
      }
  
      public PreparedStatement prepareStatement(String sql, int resultSetType,
  				       int resultSetConcurrency, int resultSetHoldability)
  	throws SQLException {
          throw new UnsupportedOperationException();
      }
  
      public CallableStatement prepareCall(String sql, int resultSetType,
  				  int resultSetConcurrency,
  				  int resultSetHoldability) throws SQLException {
          throw new UnsupportedOperationException();
      }
  
      public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
  	throws SQLException {
          throw new UnsupportedOperationException();
      }
  
      public PreparedStatement prepareStatement(String sql, int columnIndexes[])
  	throws SQLException {
          throw new UnsupportedOperationException();
      }
  
      public PreparedStatement prepareStatement(String sql, String columnNames[])
  	throws SQLException {
          throw new UnsupportedOperationException();
      }
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a new GenericConnection wrapping the specified connection.
       *
       * @param source The data source that owns this connection
       * @param conn The connection to wrap
       * @param autoCommit Desired auto-commit state for this connection
       * @param readOnly Desired read-only state for this connection
       *
       * @exception SQLException if an SQL processing error occurs
       */
      public GenericConnection(GenericDataSource source, Connection conn,
                               boolean autoCommit, boolean readOnly)
          throws SQLException {
  
          super();
          this.source = source;
          this.conn = conn;
  
          this.autoCommit = autoCommit;
          this.catalog = conn.getCatalog();
          this.level = conn.getTransactionIsolation();
          try {
              this.map = conn.getTypeMap();
          } catch (SQLException e) {
              ;   // PostgreSQL throws a "not yet implemented" exception
          } catch (UnsupportedOperationException e) {
              ;   // JDBC-ODBC bridge throws this
          } catch (AbstractMethodError e) {
              ;   // mm.mysql throws this
          }
  	this.readOnly = readOnly;
          this.conn.setAutoCommit(this.autoCommit);
  	try {
  	    this.conn.setReadOnly(this.readOnly);
  	} catch (SQLException e) {
  	    ;  // Informix throws a "not supported" exception
  	}
  
  
      }
  
  
      // ----------------------------------------------------- Instance Constants
  
  
      private final static String SQLEXCEPTION_CLOSED = "Connection was closed.";
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The initial auto-commit state to which we should return after release.
       */
      protected boolean autoCommit = false;
  
  
      /**
       * The initial catalog to which we should return after release.
       */
      protected String catalog = null;
  
  
      /**
       * The closed flag for this wrapped connection.
       */
      private boolean closed = false;
  
  
      /**
       * The Connection that is being wrapped.
       */
      protected Connection conn = null;
  
  
      /**
       * The initial transaction isolation level to which we should return
       * after release.
       */
      protected int level = 0;
  
  
      /**
       * The initial type map to which we should return after release.
       */
      protected Map map = null;
  
  
      /**
       * The initial read-only state to which we should return after release.
       */
      protected boolean readOnly = false;
  
  
      /**
       * The GenericDataSource that owns this connection.
       */
      protected GenericDataSource source = null;
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Clear all warnings reported for this Connection.
       *
       * @exception SQLException if a database access error occurs
       */
      public void clearWarnings() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          conn.clearWarnings();
  
      }
  
  
      /**
       * Return this wrapped Connection to our data source connection pool.
       *
       * @exception SQLException if a database access error occurs
       */
      public void close() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          // Clean up any outstanding transaction as best we can
          try {
              conn.rollback();
          } catch (SQLException e) {
              ;
          }
          try {
              conn.setAutoCommit(this.autoCommit);
          } catch (SQLException e) {
              ;
          }
          try {
              conn.setCatalog(this.catalog);
          } catch (SQLException e) {
              ;
          }
          try {
              conn.setTransactionIsolation(this.level);
          } catch (SQLException e) {
              ;
          }
          try {
              conn.setTypeMap(this.map);
          } catch (SQLException e) {
              ;   // PostgreSQL throws a "not yet implemented" exception
          } catch (UnsupportedOperationException e) {
              ;   // JDBC-ODBC driver throws this
          } catch (AbstractMethodError e) {
              ;   // mm.mysql throws this
          }
          try {
              conn.setReadOnly(this.readOnly);
          } catch (SQLException e) {
              ;   // Informix throws a "not supported" exception
          }
          try {
              conn.clearWarnings();
          } catch (SQLException e) {
              ;
          }
  
          // Flag that this connection is closed
          // All methods accessing conn will now throw SQLEXCEPTION_CLOSED
          closed = true;
  
          // Return this connection to the available connection pool
          source.returnConnection(this);
  
      }
  
  
      /**
       * Make all changes made since the previous commit or rollback
       * permanent, and releases any database locks currently held.
       *
       * @exception SQLException if a database access error occurs
       */
      public void commit() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          conn.commit();
  
      }
  
  
      /**
       * Create a <code>Statement</code> for sending SQL statements to the
       * database.
       *
       * @exception SQLException if a database access error occurs
       */
      public Statement createStatement() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.createStatement());
  
      }
  
  
  
      /**
       * (JDBC 2.0) Create a Statement that will create a ResultSet of the
       * specified type and concurrency.
       *
       * @param resultSetType A result set type
       * @param resultSetConcurrency A result set concurrency
       *
       * @exception SQLException if a database access error occurs
       */
      public Statement createStatement(int resultSetType,
                                       int resultSetConcurrency)
          throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.createStatement(resultSetType, resultSetConcurrency));
  
      }
  
  
      /**
       * Return the current auto-commit state.
       *
       * @exception SQLException if a database access error occurs
       */
      public boolean getAutoCommit() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.getAutoCommit());
  
      }
  
  
      /**
       * Return the current catalog name for this Connection.
       *
       * @exception SQLException if a database access error occurs
       */
  
  
      public String getCatalog() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.getCatalog());
  
      }
  
  
      /**
       * Get the metadata regarding this connection's database.
       *
       * @exception SQLException if a database access error occurs
       */
      public DatabaseMetaData getMetaData() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.getMetaData());
  
      }
  
  
      /**
       * Return this Connection's current transaction isolation level.
       *
       * @exception SQLException if a database access error occurs
       */
      public int getTransactionIsolation() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.getTransactionIsolation());
  
      }
  
  
      /**
       * (JDBC 2.0) Return the type map for this connection.
       *
       * @exception SQLException if a database access error occurs
       */
      public Map getTypeMap() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.getTypeMap());
  
      }
  
  
      /**
       * Return the first warning reported by calls to this Connection.
       *
       * @exception SQLException if a database access error occurs
       */
      public SQLWarning getWarnings() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.getWarnings());
  
      }
  
  
      /**
       * Return <code>true</code> if this Connection is closed.
       *
       * The GenericConnection.isClosed() method is only guaranteed to return true after
       * GenericConnection.closed() has been called. This method cannot be called, in
       * general, to determine if a database connection is valid or invalid.
       *
       * A typical JDBC client can determine that a connection is invalid by catching the
       * exception that is thrown when a JDBC operation is attempted.
       *
       * @exception SQLException if a database access error occurs
       */
  
  
      public boolean isClosed() throws SQLException {
  
        return (closed);
  
      }
  
  
      /**
       * Return <code>true</code> if this Connection is in read-only mode.
       *
       * @exception SQLException if a database access error occurs
       */
      public boolean isReadOnly() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.isReadOnly());
  
      }
  
  
      /**
       * Convert the given SQL statement into the system's native SQL grammer.
       *
       * @param sql Statement to be processed
       */
      public String nativeSQL(String sql) throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.nativeSQL(sql));
  
      }
  
  
      /**
       * Create a <code>CallableStatement</code> object for calling database
       * stored procedures.
       *
       * @param sql Statement to be processed
       *
       * @exception SQLException if a database access error occurs
       */
      public CallableStatement prepareCall(String sql) throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.prepareCall(sql));
  
      }
  
  
      /**
       * (JDBC 2.0) Create a CallableStatement object that will generate
       * ResultSet objects with the given type and concurrency.
       *
       * @param sql Statement to be processed
       * @param resultSetType A result set type
       * @param resultSetConcurrency A result set concurrency
       *
       * @exception SQLException if a database access error occurs
       */
      public CallableStatement prepareCall(String sql, int resultSetType,
                                           int resultSetConcurrency)
          throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.prepareCall(sql, resultSetType, resultSetConcurrency));
  
      }
  
  
      /**
       * Create a <code>PreparedStatement</code> object for sending
       * parameterized SQL statements to the database.
       *
       * @param sql Statement to be processed
       *
       * @exception SQLException if a database access error occurs
       */
      public PreparedStatement prepareStatement(String sql) throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.prepareStatement(sql));
  
      }
  
  
      /**
       * (JDBC 2.0) Create a PreparedStatement object that will generate
       * ResultSet objects with the given type and concurrency.
       *
       * @param sql Statement to be processed
       * @param resultSetType A result set type
       * @param resultSetConcurrency A result set concurrency
       *
       * @exception SQLException if a database access error occurs
       */
      public PreparedStatement prepareStatement(String sql, int resultSetType,
                                                int resultSetConcurrency)
          throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          return (conn.prepareStatement(sql, resultSetType,
                                        resultSetConcurrency));
  
      }
  
  
      /**
       * Drop all changes made since the previous commit or rollback.
       *
       * @exception SQLException if a database access error occurs
       */
      public void rollback() throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          conn.rollback();
  
      }
  
  
      /**
       * Sets this connection's auto-commit mode.
       *
       * @param autoCommit The new auto-commit mode.
       *
       * @exception SQLException if a database access error occurs
       */
      public void setAutoCommit(boolean autoCommit) throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          conn.setAutoCommit(autoCommit);
  
      }
  
  
      /**
       * Set the catalog name for this Connection.
       *
       * @param catalog The new catalog name
       *
       * @exception SQLException if a database access error occurs
       */
      public void setCatalog(String catalog) throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          conn.setCatalog(catalog);
  
      }
  
  
      /**
       * Set the read-only mode of this connection.
       *
       * @param readOnly The new read-only mode
       *
       * @exception SQLException if a database access error occurs
       */
      public void setReadOnly(boolean readOnly) throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          conn.setReadOnly(readOnly);
  
      }
  
  
      /**
       * Set the transaction isolation level for this Connection.
       *
       * @param level The new transaction isolation level
       *
       * @exception SQLException if a database access error occurs
       */
      public void setTransactionIsolation(int level) throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          conn.setTransactionIsolation(level);
  
      }
  
  
      /**
       * (JDBC 2.0) Set the type map for this connection.
       *
       * @param map The new type map
       *
       * @exception SQLException if a database access error occurs
       */
      public void setTypeMap(Map map) throws SQLException {
  
          if (closed) throw new SQLException(SQLEXCEPTION_CLOSED);
  
          conn.setTypeMap(map);
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      /**
       * Return the actual connection that we are wrapping.
       */
      Connection getConnection() {
  
          return (this.conn); // FIXME - Good idea to return if closed?
  
      }
  
  
      /**
       * Return the data source that owns this connection.
       */
      DataSource getDataSource() {
  
          // Do not check for closed exception, to allow for a fresh connection
  
          return (this.source);
  
      }
  
  
      /**
       * Set the closed status of this connection wrapper.
       *
       * Would usually only be called by the owning DataSource (source), with
       * setClosed(false), when a pooled connection is being recycled.
       *
       */
      void setClosed(boolean closed) {
  
          this.closed = closed;
  
      }
  
  
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: struts-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: struts-dev-help@jakarta.apache.org