FileDocCategorySizeDatePackage
DBUtil.javaAPI DocExample5607Sun Sep 02 14:59:06 BST 2001com.oreilly.forum.jdbcimpl

DBUtil.java

package com.oreilly.forum.jdbcimpl;

import java.io.*;
import java.sql.*;
import java.util.*;

/**
 * Helper methods for relational database access using JDBC.
 */
public class DBUtil {
    // buffer size when reading long strings
    private static final int BUF_SIZE = 250;

    // a map of table names to maximum ID numbers
    private static Map tableToMaxIDMap = new HashMap();

    /**
     * Close a statement and connection.
     */
    public static void close(Statement stmt, Connection con) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (Exception ignored1) {
            }
        }
        if (con != null) {
            try {
                // return the connection to the pool
                putPooledConnection(con);
            } catch (Exception ignored2) {
            }
        }
    }

    /**
     * @return a new Connection to the database.
     */
    public static Connection getConnection(String dbURL)
            throws SQLException {
        // get a connection from the pool
        return getPooledConnection(dbURL);
    }

    /**
     * Close any connections that are still open. The Servlet will
     * call this method from its destroy() method.
     */
    public static void closeAllConnections() {
        // empty the connection pool and close all connections
        emptyPool();
    }


    /**
     * Store a long text field in the database. For example, a message's
     * text will be quite long and cannot be stored using JDBC's
     * setString() method.
     */
    public static void setLongString(PreparedStatement stmt,
            int columnIndex, String data) throws SQLException {
        if (data.length() > 0) {
            stmt.setAsciiStream(columnIndex,
                    new ByteArrayInputStream(data.getBytes()),
                    data.length());
        } else {
            // this 'else' condition was introduced as a bug fix.  It was
            // discovered that the 'setAsciiStream' code shown above
            // caused MS Access to throw a "function sequence error"
            // when the string was zero length.  This code now works.
            stmt.setString(columnIndex, "");
        }
    }


    /**
     * @return a long text field from the database.
     */
    public static String getLongString(ResultSet rs, int columnIndex)
            throws SQLException {
        try {
            InputStream in = rs.getAsciiStream(columnIndex);
            if (in == null) {
                return "";
            }

            byte[] arr = new byte[BUF_SIZE];
            StringBuffer buf = new StringBuffer();
            int numRead = in.read(arr);
            while (numRead != -1) {
                buf.append(new String(arr, 0, numRead));
                numRead = in.read(arr);
            }
            return buf.toString();
        } catch (IOException ioe) {
            ioe.printStackTrace();
            throw new SQLException(ioe.getMessage());
        }
    }

    /**
     * Compute a new unique ID. It is assumed that the specified table
     * has a column named 'id' of type 'long'. It is assumed that
     * that all parts of the program will use this method to compute
     * new IDs.
     * @return the next available unique ID for a table.
     */
    public static synchronized long getNextID(String tableName,
            Connection con) throws SQLException {
        Statement stmt = null;

        try {
            // if a max has already been retreived from this table,
            // compute the next id without hitting the database
            if (tableToMaxIDMap.containsKey(tableName)) {
                Long curMax = (Long) tableToMaxIDMap.get(tableName);
                Long newMax = new Long(curMax.longValue() + 1L);
                tableToMaxIDMap.put(tableName, newMax);
                return newMax.longValue();
            }

            stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery(
                    "SELECT MAX(id) FROM " + tableName);
            long max = 0;
            if (rs.next()) {
                max = rs.getLong(1);
            }
            max++;
            tableToMaxIDMap.put(tableName, new Long(max));
            return max;
        } finally {
            // just close the statement
            close(stmt, null);
        }
    }

    //////////////////////////////////////////////////////////////////
    // a rudimentary connection pool
    private static Stack availableConnections = new Stack();

    private static synchronized Connection getPooledConnection(String dbURL)
            throws SQLException {
        if (!availableConnections.isEmpty()) {
            System.out.println("Reusing a connection");
            return (Connection) availableConnections.pop();
        } else {
            System.out.println("Creating a connection");
            return DriverManager.getConnection(dbURL);
        }
    }

    private static synchronized void putPooledConnection(Connection con) {
        availableConnections.push(con);
    }

    private static synchronized void emptyPool() {
        while (!availableConnections.isEmpty()) {
            Connection con = (Connection) availableConnections.pop();
            try {
                con.close();
            } catch (SQLException ignored) {
            }
        }
    }

    //////////////////////////////////////////////////////////////////
}