You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by cr...@locus.apache.org on 2000/11/26 06:11:31 UTC

cvs commit: jakarta-struts/src/share/org/apache/struts/util GenericConnection.java GenericDataSource.java

craigmcc    00/11/25 21:11:31

  Modified:    .        README
               src/conf struts-config_1_0.dtd
               src/doc  release.xml
               src/share/org/apache/struts/action Action.java
                        ActionResources.properties ActionServlet.java
  Added:       src/share/org/apache/struts/util GenericConnection.java
                        GenericDataSource.java
  Log:
  Initial implementation of a simple JDBC data source for Struts based
  applications.  The data source implements the javax.sql.DataSource
  interface, and may be configured by new extensions to the
  struts-config.xml DTD.  More sophisticated data source implementations may
  also be used, as long as they implement javax.sql.DataSource.
  
  Revision  Changes    Path
  1.11      +5 -1      jakarta-struts/README
  
  Index: README
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/README,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- README	2000/11/03 01:54:32	1.10
  +++ README	2000/11/26 05:11:27	1.11
  @@ -1,4 +1,4 @@
  -$Id: README,v 1.10 2000/11/03 01:54:32 craigmcc Exp $
  +$Id: README,v 1.11 2000/11/26 05:11:27 craigmcc Exp $
   
   				Struts
   				======
  @@ -48,6 +48,10 @@
     available at <http://xml.apache.org>.  Be sure to add the "jaxp.jar" and
     "parser.jar" (or whatever JAR file comes with your parser) files to
     your CLASSPATH environment variable.
  +
  +- Download and install the JDBC 2.0 Standard Extensions package from the
  +  Java Software web site <http://java.sun.com/products/jdbc>, and install
  +  the "jdbc2_0-stdext.jar" file on your classpath (or as a system extension).
   
   - (*) Download and install a servlet container that supports the Servlet
     API Specification, version 2.2 or later, and the JavaServer Pages (JSP)
  
  
  
  1.2       +62 -2     jakarta-struts/src/conf/struts-config_1_0.dtd
  
  Index: struts-config_1_0.dtd
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/conf/struts-config_1_0.dtd,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- struts-config_1_0.dtd	2000/09/20 04:16:11	1.1
  +++ struts-config_1_0.dtd	2000/11/26 05:11:28	1.2
  @@ -11,7 +11,7 @@
          "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd">
   
  -     $Id: struts-config_1_0.dtd,v 1.1 2000/09/20 04:16:11 craigmcc Exp $
  +     $Id: struts-config_1_0.dtd,v 1.2 2000/11/26 05:11:28 craigmcc Exp $
   -->
   
   
  @@ -38,6 +38,13 @@
   <!ENTITY % ClassName "CDATA">
   
   
  +<!-- An "Integer" is a character string consisting solely of numeric digits,
  +     optionally preceeded by a minus sign, that can be converted to a
  +     32-bit integer.
  +-->
  +<!ENTITY % Integer "CDATA">
  +
  +
   <!-- A "Location" is a relative path, delimited by "/" characters, that
        defines the location of a resource relative to the location of the
        Struts configuration file itself.
  @@ -72,8 +79,61 @@
        hierarchy, and contains nested elements for all of the other
        configuration settings.
   -->
  -<!ELEMENT struts-config (form-beans?, global-forwards?, action-mappings?)>
  +<!ELEMENT struts-config (data-source, form-beans?, global-forwards?, action-mappings?)>
   <!ATTLIST struts-config  id             ID              #IMPLIED>
  +
  +
  +<!-- The "data-source" element describes a JDBC 2.0 Standard Extension data
  +     source object (that implements javax.sql.DataSource) which will be
  +     configured according to the properties and nested elements found here,
  +     and made available as a servlet context attribute (i.e. application
  +     scope bean).  The following attributes are defined:
  +
  +     type            Fully qualified Java class name of the implementation
  +                     class (must implement javax.sql.DataSource).
  +
  +     NOTE:  The following attributes are defined by the default data source
  +     implementation, and only take effect for that class or subclasses of
  +     that class.
  +
  +     autoCommit      The default auto-commit state for newly created
  +                     connections.
  +
  +     description     The description of this data source.
  +
  +     driverClass     The Java class name of the JDBC driver to be used.
  +                     [REQUIRED]
  +
  +     loginTimeout    The maximum number of seconds to wait for a connection
  +                     to be created or returned.
  +
  +     maxCount        The maximum number of connections to be created.
  +
  +     minCount        The minimum number of connections to be created.
  +
  +     password        The database password to use when connecting. [REQUIRED]
  +
  +     readOnly        The default read-only state for newly created
  +                     connections.
  +
  +     url             The JDBC URL to use when connecting. [REQUIRED]
  +
  +     user            The database username to use when connecting. [REQUIRED]
  +
  +-->
  +<!ELEMENT data-source (set-property*)>
  +<!ATTLIST data-source    id             ID              #IMPLIED>
  +<!ATTLIST data-source    type           %ClassName;     "org.apache.struts.util.GenericDataSource">
  +<!ATTLIST data-source    autoCommit     %Boolean;       "true">
  +<!ATTLIST data-source    description    CDATA           #IMPLIED>
  +<!ATTLIST data-source    driverClass    %ClassName;     #REQUIRED>
  +<!ATTLIST data-source    loginTimeout   %Integer;       #IMPLIED>
  +<!ATTLIST data-source    maxCount       %Integer;       "2">
  +<!ATTLIST data-source    minCount       %Integer;       "1">
  +<!ATTLIST data-source    password       CDATA           #REQUIRED>
  +<!ATTLIST data-source    readOnly       %Boolean;       "false">
  +<!ATTLIST data-source    url            CDATA           #REQUIRED>
  +<!ATTLIST data-source    user           CDATA           #REQUIRED>
   
   
   <!-- The "form-beans" element is the root of the set of form bean descriptors
  
  
  
  1.11      +11 -0     jakarta-struts/src/doc/release.xml
  
  Index: release.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/doc/release.xml,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- release.xml	2000/11/19 03:12:01	1.10
  +++ release.xml	2000/11/26 05:11:29	1.11
  @@ -70,6 +70,17 @@
         properties) only if the checkbox was actually checked.</li>
     </ul>
   
  +  <p>The following major new features have been added to the utility classes
  +  library (package <code>org.apache.struts.util</code>):</p>
  +  <ul>
  +  <li>Initial implementation of a JDBC data source that implements the
  +      <code>javax.sql.DataSource</code> interface from the JDBC 2.0 Standard
  +      Extensions API.  This implementation may be configured based on new
  +      extensions to the Struts configuration file DTD, and the configured
  +      data source / connection pool is made available to application components
  +      as a servlet context attribute (i.e. an application scope bean).</li>
  +  </ul>
  +
     <p>The following major new features have been added to the
     <em>struts-bean</em> custom tag library (package
     <code>org.apache.struts.taglib.bean</code>):</p>
  
  
  
  1.9       +13 -4     jakarta-struts/src/share/org/apache/struts/action/Action.java
  
  Index: Action.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- Action.java	2000/11/18 22:10:55	1.8
  +++ Action.java	2000/11/26 05:11:30	1.9
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.8 2000/11/18 22:10:55 craigmcc Exp $
  - * $Revision: 1.8 $
  - * $Date: 2000/11/18 22:10:55 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/Action.java,v 1.9 2000/11/26 05:11:30 craigmcc Exp $
  + * $Revision: 1.9 $
  + * $Date: 2000/11/26 05:11:30 $
    *
    * ====================================================================
    *
  @@ -105,13 +105,22 @@
    * by this Action.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.8 $ $Date: 2000/11/18 22:10:55 $
  + * @version $Revision: 1.9 $ $Date: 2000/11/26 05:11:30 $
    */
   
   public class Action {
   
   
       // ----------------------------------------------------- Manifest Constants
  +
  +
  +    /**
  +     * The context attribute key under which our configured data source
  +     * (which must implement <code>javax.sql.DataSource</code>) is stored,
  +     * if one is configured for this application.
  +     */
  +    public static final String DATA_SOURCE_KEY =
  +      "org.apache.struts.action.DATA_SOURCE";
   
   
       /**
  
  
  
  1.5       +4 -0      jakarta-struts/src/share/org/apache/struts/action/ActionResources.properties
  
  Index: ActionResources.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionResources.properties,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ActionResources.properties	2000/10/15 03:29:15	1.4
  +++ ActionResources.properties	2000/11/26 05:11:30	1.5
  @@ -6,7 +6,11 @@
   configMapping=Configuring mapping for path {0}
   configMissing=Missing configuration resource for path {0}
   configParse=Parsing error processing resource path {0}
  +dataSource.destroy=Finalizing application data source
  +dataSource.init=Initializing application data source
  +destroyDataSource=Exception destroying application data source
   finalizing=Finalizing this controller servlet
  +initDataSource=Exception initializing application data source
   noInput=No input attribute for mapping path {0}
   processInvalid=Invalid path {0} was requested
   processPath=No process path included in this request
  
  
  
  1.36      +97 -4     jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java
  
  Index: ActionServlet.java
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v
  retrieving revision 1.35
  retrieving revision 1.36
  diff -u -r1.35 -r1.36
  --- ActionServlet.java	2000/11/19 02:11:15	1.35
  +++ ActionServlet.java	2000/11/26 05:11:30	1.36
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.35 2000/11/19 02:11:15 craigmcc Exp $
  - * $Revision: 1.35 $
  - * $Date: 2000/11/19 02:11:15 $
  + * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.36 2000/11/26 05:11:30 craigmcc Exp $
  + * $Revision: 1.36 $
  + * $Date: 2000/11/26 05:11:30 $
    *
    * ====================================================================
    *
  @@ -66,6 +66,7 @@
   import java.io.InputStream;
   import java.io.IOException;
   import java.net.URL;
  +import java.sql.SQLException;
   import java.util.Hashtable;
   import java.util.Enumeration;
   import java.util.Locale;
  @@ -78,9 +79,11 @@
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
   import javax.servlet.http.HttpSession;
  +import javax.sql.DataSource;
   import org.apache.struts.digester.Digester;
   import org.apache.struts.taglib.form.Constants;
   import org.apache.struts.util.BeanUtils;
  +import org.apache.struts.util.GenericDataSource;
   import org.apache.struts.util.MessageResources;
   import org.xml.sax.SAXException;
   
  @@ -200,7 +203,7 @@
    * </ul>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.35 $ $Date: 2000/11/19 02:11:15 $
  + * @version $Revision: 1.36 $ $Date: 2000/11/26 05:11:30 $
    */
   
   public class ActionServlet
  @@ -237,6 +240,13 @@
   
   
       /**
  +     * The JDBC data source that has been configured for this application,
  +     * if any.
  +     */
  +    protected DataSource dataSource = null;
  +
  +
  +    /**
        * The debugging detail level for this servlet.
        */
       protected int debug = 0;
  @@ -372,6 +382,7 @@
   
           destroyActions();
   	destroyApplication();
  +        destroyDataSource();
   	destroyInternal();
   
       }
  @@ -396,6 +407,7 @@
   		(internal.getMessage("configIO", config));
   	}
           initUpload();
  +        initDataSource();
   	initOther();
   
       }
  @@ -522,7 +534,9 @@
        * @return The size in bytes of the buffer
        */
       public int getBufferSize() {
  +
           return bufferSize;
  +
       }
   
   
  @@ -538,6 +552,16 @@
   
   
       /**
  +     * Return the JDBC data source associated with this application, if any.
  +     */
  +    public DataSource getDataSource() {
  +
  +        return (this.dataSource);
  +
  +    }
  +
  +
  +    /**
        * Return the Java class name of the class used to instantiate
        * <code>ActionFormBean</code> objects.
        */
  @@ -697,7 +721,21 @@
        * @param bufferSize The size in bytes of the buffer
        */
       public void setBufferSize(int bufferSize) {
  +
           this.bufferSize = bufferSize;
  +
  +    }
  +
  +
  +    /**
  +     * Set the data source object to be used by this application.
  +     *
  +     * @param dataSource The data source to be used
  +     */
  +    public void setDataSource(DataSource dataSource) {
  +
  +        this.dataSource = dataSource;
  +
       }
   
   
  @@ -807,6 +845,29 @@
   
   
       /**
  +     * Gracefully terminate use of the data source associated with this
  +     * application (if any).
  +     */
  +    protected void destroyDataSource() {
  +
  +        if (dataSource == null)
  +            return;
  +        if (dataSource instanceof GenericDataSource) {
  +            if (debug >= 1)
  +                log(internal.getMessage("dataSource.destroy"));
  +            try {
  +                ((GenericDataSource) dataSource).close();
  +            } catch (SQLException e) {
  +                log(internal.getMessage("destroyDataSource"), e);
  +            }
  +            dataSource = null;
  +            getServletContext().removeAttribute(Action.DATA_SOURCE_KEY);
  +        }
  +
  +    }
  +
  +
  +    /**
        * Gracefully terminate use of the internal MessageResources.
        */
       protected void destroyInternal() {
  @@ -849,6 +910,29 @@
   
   
       /**
  +     * Initialize use of the data source associated with this
  +     * application (if any).
  +     */
  +    protected void initDataSource() {
  +
  +        if (dataSource == null)
  +            return;
  +        if (dataSource instanceof GenericDataSource) {
  +            if (debug >= 1)
  +                log(internal.getMessage("dataSource.init"));
  +            try {
  +                ((GenericDataSource) dataSource).open();
  +            } catch (SQLException e) {
  +                log(internal.getMessage("initDataSource"), e);
  +            }
  +            getServletContext().setAttribute(Action.DATA_SOURCE_KEY,
  +                                             dataSource);
  +        }
  +
  +    }
  +
  +
  +    /**
        * Initialize the debugging detail level for this application.
        *
        * @exception ServletException if we cannot initialize these resources
  @@ -886,6 +970,15 @@
   	// Configure the processing rules
   
           // FIXME "struts-config/action-mappings" type attribute
  +
  +        digester.addObjectCreate("struts-config/data-source",
  +                                 "org.apache.struts.util.GenericDataSource",
  +                                 "type");
  +        digester.addSetProperties("struts-config/data-source");
  +        digester.addSetNext("struts-config/data-source",
  +                            "setDataSource", "javax.sql.DataSource");
  +        digester.addSetProperty("struts-config/data-source/set-property",
  +                                "property", "value");
   
           digester.addObjectCreate("struts-config/action-mappings/action",
                                    mappingClass, "className");
  
  
  
  1.1                  jakarta-struts/src/share/org/apache/struts/util/GenericConnection.java
  
  Index: GenericConnection.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/GenericConnection.java,v 1.1 2000/11/26 05:11:31 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/11/26 05:11:31 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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.util;
  
  
  import java.sql.CallableStatement;
  import java.sql.Connection;
  import java.sql.DatabaseMetaData;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.sql.SQLWarning;
  import java.sql.Statement;
  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.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/11/26 05:11:31 $
   */
  
  public class GenericConnection implements Connection {
  
  
  
      // ----------------------------------------------------------- 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
          }
          this.readOnly = readOnly;
  
          this.conn.setAutoCommit(this.autoCommit);
          this.conn.setReadOnly(this.readOnly);
  
      }
  
  
      // ----------------------------------------------------- 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 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 {
  
          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 {
  
          // 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) {
              ;
          }
          try {
              conn.setReadOnly(this.readOnly);
          } catch (SQLException e) {
              ;
          }
          try {
              conn.clearWarnings();
          } catch (SQLException e) {
              ;
          }
  
          // 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 {
  
          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 {
  
          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 {
  
          return (conn.createStatement(resultSetType, resultSetConcurrency));
  
      }
  
  
      /**
       * Return the current auto-commit state.
       *
       * @exception SQLException if a database access error occurs
       */
      public boolean getAutoCommit() throws SQLException {
  
          return (conn.getAutoCommit());
  
      }
  
  
      /**
       * Return the current catalog name for this Connection.
       *
       * @exception SQLException if a database access error occurs
       */
      public String getCatalog() throws SQLException {
  
          return (conn.getCatalog());
  
      }
  
  
      /**
       * Get the metadata regarding this connection's database.
       *
       * @exception SQLException if a database access error occurs
       */
      public DatabaseMetaData getMetaData() throws SQLException {
  
          return (conn.getMetaData());
  
      }
  
  
      /**
       * Return this Connection's current transaction isolation level.
       *
       * @exception SQLException if a database access error occurs
       */
      public int getTransactionIsolation() throws SQLException {
  
          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 {
  
          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 {
  
          return (conn.getWarnings());
  
      }
  
  
      /**
       * Return <code>true</code> if this Connection is closed.
       *
       * @exception SQLException if a database access error occurs
       */
      public boolean isClosed() throws SQLException {
  
          return (false); // FIXME - isClosed()
  
      }
  
  
      /**
       * 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 {
  
          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 {
  
          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 {
  
          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 {
  
          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 {
  
          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 {
  
          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 {
  
          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 {
  
          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 {
  
          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 {
  
          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 {
  
          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 {
  
          conn.setTypeMap(map);
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      /**
       * Return the actual connection that we are wrapping.
       */
      Connection getConnection() {
  
          return (this.conn);
  
      }
  
  
      /**
       * Return the data source that owns this connection.
       */
      DataSource getDataSource() {
  
          return (this.source);
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-struts/src/share/org/apache/struts/util/GenericDataSource.java
  
  Index: GenericDataSource.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/util/GenericDataSource.java,v 1.1 2000/11/26 05:11:31 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/11/26 05:11:31 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 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", "Tomcat", 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.util;
  
  
  import java.io.PrintWriter;
  import java.sql.Connection;
  import java.sql.Driver;
  import java.sql.SQLException;
  import java.util.LinkedList;
  import java.util.Properties;
  import javax.sql.DataSource;
  
  
  /**
   * 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.  It
   * always returns connections based on the username and password configured
   * with <code>setUsername()</code> and <code>setPassword()</code>,
   * respectively.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/11/26 05:11:31 $
   */
  
  public class GenericDataSource implements DataSource {
  
  
      // ----------------------------------------------------- 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;
  
  
      /**
       * The login timeout for this data source.
       */
      protected int loginTimeout = 0;
  
  
      /**
       * The log writer for this data source.
       */
      protected PrintWriter logWriter = null;
  
  
      /**
       * The connection properties for use in establishing connections.
       */
      protected Properties properties = new Properties();
  
  
      // ------------------------------------------------------------- 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 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 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;
  
          // 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 ((loginTimeout > 0) && (seconds >= loginTimeout))
                  break;
  
              // Return an existing connection from the pool if there is one
              synchronized (connections) {
                  if (!connections.isEmpty()) {
                      useCount++;
                      return ((Connection) connections.removeFirst());
                  }
              }
  
              // Create a new connection if we are not yet at the maximum
              if (activeCount < maxCount) {
                  Connection conn = createConnection();
                  useCount++;
                  return (conn);
              }
  
              // Wait for an existing connection to be returned
              try {
                  Thread.sleep(1000);
                  seconds++;
              } catch (InterruptedException e) {
                  ;
              }
  
          }
  
          // We have timed out awaiting an available connection
          throw new SQLException
              ("getConnection: Timeout awaiting connection");
  
      }
  
  
      /**
       * Attempt to establish a database connection.  <b>WARNING</b> - The
       * specified username and password are ignored 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 {
  
          return (getConnection());
  
      }
  
  
      /**
       * 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");
  
          // 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;
  
          // Instantiate our database driver
          try {
              Class clazz = Class.forName(driverClass);
              driver = (Driver) clazz.newInstance();
          } catch (Throwable t) {
              throw new SQLException("createConnection: " + 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 {
  
          Connection conn = driver.connect(url, properties);
          activeCount++;
          return (new GenericConnection(this, conn, autoCommit, readOnly));
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      /**
       * Return this connection to the available connection pool.
       *
       * @param conn The connection being returned
       */
      void returnConnection(GenericConnection conn) {
  
          synchronized (connections) {
              connections.addLast(conn);
              useCount--;
          }
  
      }
  
  
  }