一个连接池的例子(来自JIVE)(3)

//文件:DbConnectionDefaultPool.java的第三部分


        /**
         * Returns the age of a connection -- the time since it was handed out to
         * an application.
         */
        public long getAge(Connection conn) { // Returns the age of the connection in millisec.
            int thisconn = idOfConnection(conn);
            return System.currentTimeMillis() - connLockTime[thisconn];
        }

        private void createConn(int i) throws SQLException {
             Date now = new Date();
             try {
                Class.forName (dbDriver);
                Properties dbProp = new Properties();
                //log.println("Creating.....");
                dbProp.put("user", dbLogin);
                dbProp.put("password", dbPassword);
                dbProp.put("characterEncoding","gb2112");
                //dbProp.put("useUnicode", "true");
        
                connPool[i] = DriverManager.getConnection
                          (dbServer,dbProp);
                //log.println("Created Ok...");
                connStatus[i]=0;
                connID[i]=connPool[i].toString();
                connLockTime[i]=0;
                connCreateDate[i] =  now.getTime();
            }
            catch (ClassNotFoundException e2) {}
                
            log.println(now.toString() + "  Opening connection " + String.valueOf(i) +
                    " " + connPool[i].toString() + ":");
        }
    
        /**
         * Shuts down the housekeeping thread and closes all connections
         * in the pool. Call this method from the destroy() method of the servlet.
         */

        /**
         * Multi-phase shutdown.  having following sequence:
         * <OL>
         * <LI><code>getConnection()</code> will refuse to return connections.
         * <LI>The housekeeping thread is shut down.<br>
         *    Up to the time of <code>millis</code> milliseconds after shutdown of
         *    the housekeeping thread, <code>freeConnection()</code> can still be
         *    called to return used connections.
         * <LI>After <code>millis</code> milliseconds after the shutdown of the
         *    housekeeping thread, all connections in the pool are closed.
         * <LI>If any connections were in use while being closed then a
         *    <code>SQLException</code> is thrown.
         * <LI>The log is closed.
         * </OL><br>
         * Call this method from a servlet destroy() method.
         *
         * @param      millis   the time to wait in milliseconds.
         * @exception  SQLException if connections were in use after
         * <code>millis</code>.
         */
        public void destroy(int millis) throws SQLException {
    
            // Checking for invalid negative arguments is not necessary,
            // Thread.join() does this already in runner.join().

            // Stop issuing connections
            available=false;

            // Shut down the background housekeeping thread
            runner.interrupt();

            // Wait until the housekeeping thread has died.
            try { runner.join(millis); }
            catch(InterruptedException e){} // ignore
        
            // The housekeeping thread could still be running
            // (e.g. if millis is too small). This case is ignored.
            // At worst, this method will throw an exception with the
            // clear indication that the timeout was too short.

            long startTime=System.currentTimeMillis();

            // Wait for freeConnection() to return any connections
            // that are still used at this time.
            int useCount;
            while((useCount=getUseCount())>0 && System.currentTimeMillis() - startTime <=  millis) {
                try { Thread.sleep(500); }
                catch(InterruptedException e) {} // ignore
            }

            // Close all connections, whether safe or not
            for(int i=0; i < currConnections; i++) {
                try {
                    connPool[i].close();
                }
                catch (SQLException e1)
                {
                    log.println("Cannot close connections on Destroy");
                }
            }

            if(useCount > 0) {
                //bt-test successful
                String msg="Unsafe shutdown: Had to close "+useCount+
                    " active DB connections after "+millis+"ms";
                log.println(msg);
                // Close all open files
                log.close();
                // Throwing following Exception is essential because servlet authors
                // are likely to have their own error logging requirements.
                throw new SQLException(msg);
            }

            // Close all open files
            log.close();

        }//End destroy()


        /**
         * Less safe shutdown.  Uses default timeout value.
         * This method simply calls the <code>destroy()</code> method
         * with a <code>millis</code>
         * value of 10000 (10 seconds) and ignores <code>SQLException</code>
         * thrown by that method.
         * @see     #destroy(int)
         */
        public void destroy() {
            try {
                destroy(10000);
            }
            catch(SQLException e) {}
        }

        /**
         * Returns the number of connections in use.
         */
        // This method could be reduced to return a counter that is
        // maintained by all methods that update connStatus.
        // However, it is more efficient to do it this way because:
        // Updating the counter would put an additional burden on the most
        // frequently used methods; in comparison, this method is
        // rarely used (although essential).
        public int getUseCount() {
            int useCount=0;
            synchronized(connStatus) {
                for(int i=0; i < currConnections; i++) {
                    if(connStatus[i] > 0) { // In use
                        useCount++;
                    }
                }
            }
            return useCount;
        }//End getUseCount()

        /**
         * Returns the number of connections in the dynamic pool.
         */
        public int getSize() {
            return currConnections;
        }//End getSize()

    }

    /**
     * An implementation of the Connection interface that wraps an underlying
     * Connection object. It releases the connection back to a connection pool
     * when Connection.close() is called.
     */
    public class ConnectionWrapper  implements Connection {

        private Connection connection;
        private ConnectionPool connectionPool;

        public ConnectionWrapper(Connection connection, ConnectionPool connectionPool) {
            this.connection = connection;
            this.connectionPool = connectionPool;
        }

        /**
         * Instead of closing the underlying connection, we simply release
         * it back into the pool.
         */
        public void close() throws SQLException {
            connectionPool.freeConnection(this.connection);
            //Release object references. Any further method calls on the
            //connection will fail.
            connection = null;
            connectionPool = null;
        }

        public Statement createStatement() throws SQLException {
            return connection.createStatement();
        }

        public PreparedStatement prepareStatement(String sql) throws SQLException {
            return connection.prepareStatement(sql);
        }

        public CallableStatement prepareCall(String sql) throws SQLException {
            return connection.prepareCall(sql);
        }

        public String nativeSQL(String sql) throws SQLException {
            return connection.nativeSQL(sql);
        }

        public void setAutoCommit(boolean autoCommit) throws SQLException {
            connection.setAutoCommit(autoCommit);
        }

        public boolean getAutoCommit() throws SQLException {
            return connection.getAutoCommit();
        }

        public void commit() throws SQLException {
            connection.commit();
        }

        public void rollback() throws SQLException {
            connection.rollback();
        }

        public boolean isClosed() throws SQLException {
            return connection.isClosed();
        }

        public DatabaseMetaData getMetaData() throws SQLException {
            return connection.getMetaData();
        }

        public void setReadOnly(boolean readOnly) throws SQLException {
            connection.setReadOnly(readOnly);
        }

        public boolean isReadOnly() throws SQLException {
            return connection.isReadOnly();
        }

        public void setCatalog(String catalog) throws SQLException {
            connection.setCatalog(catalog);
        }

        public String getCatalog() throws SQLException {
            return connection.getCatalog();
        }

        public void setTransactionIsolation(int level) throws SQLException {
            connection.setTransactionIsolation(level);
        }

        public int getTransactionIsolation() throws SQLException {
            return connection.getTransactionIsolation();
        }

        public SQLWarning getWarnings() throws SQLException {
            return connection.getWarnings();
        }

        public void clearWarnings() throws SQLException {
            connection.clearWarnings();
        }

        public Statement createStatement(int resultSetType, int resultSetConcurrency)
                throws SQLException
        {
            return connection.createStatement(resultSetType, resultSetConcurrency);
        }

        public PreparedStatement prepareStatement(String sql, int resultSetType,
                int resultSetConcurrency) throws SQLException
        {
            return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
        }

        public CallableStatement prepareCall(String sql, int resultSetType,
                int resultSetConcurrency) throws SQLException
        {
            return prepareCall(sql, resultSetType, resultSetConcurrency);
        }

        public Map getTypeMap() throws SQLException {
            return connection.getTypeMap();
        }

        public void setTypeMap(Map map) throws SQLException {
            connection.setTypeMap(map);
        }

    }
}