craigmcc    01/06/02 16:13:40

  Modified:    src/share/org/apache/struts/action ActionServlet.java
               src/share/org/apache/struts/util GenericDataSource.java
  Log:
  Port data source fix to HEAD branch.
  
  Revision  Changes    Path
  1.70      +15 -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.69
  retrieving revision 1.70
  diff -u -r1.69 -r1.70
  --- ActionServlet.java        2001/05/18 17:11:37     1.69
  +++ ActionServlet.java        2001/06/02 23:13:36     1.70
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.69 
2001/05/18 17:11:37 mschachter Exp $
  - * $Revision: 1.69 $
  - * $Date: 2001/05/18 17:11:37 $
  + * $Header: 
/home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.70 
2001/06/02 23:13:36 craigmcc Exp $
  + * $Revision: 1.70 $
  + * $Date: 2001/06/02 23:13:36 $
    *
    * ====================================================================
    *
  @@ -88,6 +88,7 @@
   import org.apache.struts.util.MessageResources;
   import org.apache.struts.util.MessageResourcesFactory;
   import org.apache.struts.util.RequestUtils;
  +import org.apache.struts.util.ServletContextWriter;
   import org.apache.struts.upload.MultipartRequestWrapper;
   import org.xml.sax.AttributeList;
   import org.xml.sax.SAXException;
  @@ -229,7 +230,7 @@
    * </ul>
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.69 $ $Date: 2001/05/18 17:11:37 $
  + * @version $Revision: 1.70 $ $Date: 2001/06/02 23:13:36 $
    */
   
   public class ActionServlet
  @@ -1054,11 +1055,21 @@
        */
       protected void initDataSources() throws ServletException {
   
  +        ServletContextWriter scw =
  +            new ServletContextWriter(getServletContext());
  +
           synchronized (dataSources) {
               Iterator keys = dataSources.keySet().iterator();
               while (keys.hasNext()) {
                   String key = (String) keys.next();
                   DataSource dataSource = findDataSource(key);
  +                try {
  +                    dataSource.setLogWriter(scw);
  +                } catch (SQLException e) {
  +                    log(internal.getMessage("initDataSource", key), e);
  +                    throw new ServletException
  +                        (internal.getMessage("initDataSource", key), e);
  +                }
                   if (dataSource instanceof GenericDataSource) {
                       if (debug >= 1)
                           log(internal.getMessage("dataSource.init", key));
  
  
  
  1.6       +246 -27   
jakarta-struts/src/share/org/apache/struts/util/GenericDataSource.java
  
  Index: GenericDataSource.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-struts/src/share/org/apache/struts/util/GenericDataSource.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- GenericDataSource.java    2001/04/18 22:15:56     1.5
  +++ GenericDataSource.java    2001/06/02 23:13:39     1.6
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-struts/src/share/org/apache/struts/util/GenericDataSource.java,v 1.5 
2001/04/18 22:15:56 craigmcc Exp $
  - * $Revision: 1.5 $
  - * $Date: 2001/04/18 22:15:56 $
  + * $Header: 
/home/cvs/jakarta-struts/src/share/org/apache/struts/util/GenericDataSource.java,v 1.6 
2001/06/02 23:13:39 craigmcc Exp $
  + * $Revision: 1.6 $
  + * $Date: 2001/06/02 23:13:39 $
    *
    * ====================================================================
    *
  @@ -66,7 +66,9 @@
   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;
  @@ -75,10 +77,8 @@
   /**
    * <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.  It
  - * always returns connections based on the username and password configured
  - * with <code>setUser()</code> and <code>setPassword()</code>,
  - * respectively. Calling this version of the implementation using the
  + * 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
  @@ -127,6 +127,26 @@
    *       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
  @@ -158,7 +178,7 @@
    *
    * @author Craig R. McClanahan
    * @author Ted Husted
  - * @version $Revision: 1.5 $ $Date: 2001/04/18 22:15:56 $
  + * @version $Revision: 1.6 $ $Date: 2001/06/02 23:13:39 $
    */
   
   public class GenericDataSource implements DataSource {
  @@ -206,13 +226,6 @@
       protected PrintWriter logWriter = null;
   
   
  -    /**
  -     * The connection properties for use in establishing connections.
  -     */
  -    protected Properties properties = new Properties();
  -
  -
  -
       // ------------------------------------------------------------- Properties
   
   
  @@ -252,6 +265,20 @@
   
   
       /**
  +     * 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;
  @@ -322,7 +349,42 @@
       }
   
   
  +
  +    /**
  +     * 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;
  @@ -387,6 +449,8 @@
       public Connection getConnection() throws SQLException {
   
           int seconds = 0;
  +        if (debug >= 2)
  +            log("  getConnection()");
   
           // Validate the opened status of this data source
           if (closed)
  @@ -397,31 +461,68 @@
           while (true) {
   
               // Have we timed out yet?
  +            if (debug >= 3)
  +                log("   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()) {
  -                    useCount++;
  -                    GenericConnection connection = (GenericConnection) 
connections.removeFirst();
  -                    // unclose the connection's wrapper
  +
  +                    // Allocate the first available connection
  +                    GenericConnection connection =
  +                        (GenericConnection) connections.removeFirst();
  +                    if (debug >= 3)
  +                        log("   Found available connection");
  +
  +                    // Make sure this connection is not stale
                       connection.setClosed(false);
  +                    try {
  +                        ping(connection);
  +                    } catch (SQLException e) {
  +                        if (debug >= 3)
  +                            log("   Connection stale, releasing");
  +                        try {
  +                            connection.getConnection().close();
  +                        } catch (SQLException f) {
  +                            ;
  +                        }
  +                        activeCount--;
  +                        continue;
  +                    }
  +
  +                    // unclose the connection's wrapper and return it
  +                    useCount++;
  +                    if (debug >= 3)
  +                        log("   Return allocated connection, activeCount=" +
  +                            activeCount + ", useCount=" + useCount);
                       return(connection);
  -                    // return ((Connection) connections.removeFirst()); DEBUG
  +
                   }
               }
   
               // Create a new connection if we are not yet at the maximum
               if (activeCount < maxCount) {
  -                Connection conn = createConnection();
  -                if (conn != null) {
  +                Connection connection = createConnection();
  +                if (connection != null) {
  +                    try {
  +                        ping(connection);
  +                    } catch (SQLException e) {
  +                        throw e;
  +                    }
                       useCount++;
  -                    return (conn);
  +                    if (debug >= 3)
  +                        log("   Return new connection, activeCount=" +
  +                            activeCount + ", useCount=" + useCount);
  +                    return (connection);
                   }
               }
   
               // Wait for an existing connection to be returned
  +            if (debug >= 3)
  +                log("   Sleep until next test");
               try {
                   Thread.sleep(1000);
                   seconds++;
  @@ -432,6 +533,8 @@
           }
   
           // We have timed out awaiting an available connection
  +        if (debug >= 3)
  +            log("   Timeout awaiting connection");
           throw new SQLException
               ("getConnection: Timeout awaiting connection");
   
  @@ -440,16 +543,14 @@
   
       /**
        * Attempt to establish a database connection.  <b>WARNING</b> - The
  -     * specified username and password are ignored by this implementation.
  +     * 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 {
   
  @@ -523,6 +624,8 @@
   
           if (closed)
               throw new SQLException("close:  Data Source already closed");
  +        if (debug >= 1)
  +            log(" close()");
   
           // Shut down all active connections
           while (activeCount > 0) {
  @@ -548,13 +651,15 @@
           // Have we already been opened?
           if (driver != null)
               return;
  +        if (debug >= 1)
  +            log(" open()");
   
           // Instantiate our database driver
           try {
               Class clazz = Class.forName(driverClass);
               driver = (Driver) clazz.newInstance();
           } catch (Throwable t) {
  -            throw new SQLException("createConnection: " + t);
  +            throw new SQLException("open: " + t);
           }
   
           // Create the initial minimum number of required connections
  @@ -621,15 +726,125 @@
       protected synchronized Connection createConnection() throws SQLException {
   
           if (activeCount < maxCount) {
  +            if (debug >= 3)
  +                log("   createConnection()");
               Connection conn = driver.connect(url, properties);
               activeCount++;
               return (new GenericConnection(this, conn, autoCommit, readOnly));
           }
  +        if (debug >= 3)
  +            log("   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 (debug >= 4)
  +                log("    ping(" + pingCommand + ")");
  +
  +            Statement stmt = conn.createStatement();
  +            try {
  +                stmt.execute(pingCommand);
  +                stmt.close();
  +            } catch (SQLException e) {
  +                if (debug >= 5)
  +                    log("     ping() failed:  " + e);
  +                try {
  +                    if (stmt != null)
  +                        stmt.close();
  +                } catch (SQLException f) {
  +                    ;
  +                }
  +                throw e;
  +            }
  +
  +        }
  +
  +        if (pingQuery != null) {
  +
  +            if (debug >= 4)
  +                log("    ping(" + pingQuery + ")");
  +
  +            ResultSet rs = null;
  +            Statement stmt = conn.createStatement();
  +            try {
  +                rs = stmt.executeQuery(pingCommand);
  +                while (rs.next()) {
  +                    ;
  +                }
  +                rs.close();
  +                stmt.close();
  +            } catch (SQLException e) {
  +                if (debug >= 5)
  +                    log("     ping() failed: " + e);
  +                try {
  +                    if (rs != null)
  +                        rs.close();
  +                } catch (SQLException f) {
  +                    ;
  +                }
  +                try {
  +                    if (stmt != null)
  +                        stmt.close();
  +                } catch (SQLException f) {
  +                    ;
  +                }
  +                throw e;
  +            }
  +
  +        }
  +
  +    }
  +
  +
       // -------------------------------------------------------- Package Methods
   
   
  @@ -639,6 +854,10 @@
        * @param conn The connection being returned
        */
       void returnConnection(GenericConnection conn) {
  +
  +        if (debug >= 2)
  +            log("  releaseConnection(), activeCount=" + activeCount +
  +                ", useCount=" + (useCount - 1));
   
           synchronized (connections) {
               connections.addLast(conn);
  
  
  

Reply via email to