CachedConnectionServlet.java Source code

Java tutorial

Introduction

Here is the source code for CachedConnectionServlet.java

Source

/*
    
Java Programming with Oracle JDBC
by Donald Bales 
ISBN: 059600088X
Publisher: O'Reilly
    
*/

/*
Defining the Table: Oracle 9i
    
The following defines a table based on Oracle 9i:
    
create table DataFiles (
id INT PRIMARY KEY,
fileName VARCHAR(20),
fileBody CLOB
);
    
Defining the Table: MySQL
    
The following defines a table based on MySQL:
    
create table DataFiles (
id INT PRIMARY KEY,
fileName VARCHAR(20),
fileBody TEXT
);
    
    
*/

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Vector;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CachedConnectionServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Cached Connection Servlet</title>");
        out.println("</head>");
        out.println("<body>");

        // let's turn on verbose output
        CacheConnection.setVerbose(true);

        // now let's get a cached connection
        Connection connection = CacheConnection.checkOut();

        Statement statement = null;
        ResultSet resultSet = null;
        String userName = null;
        try {
            // test the connection
            statement = connection.createStatement();
            resultSet = statement.executeQuery("select initcap(user) from sys.dual");
            if (resultSet.next())
                userName = resultSet.getString(1);
        } catch (SQLException e) {
            out.println("DedicatedConnection.doGet() SQLException: " + e.getMessage() + "<p>");
        } finally {
            if (resultSet != null)
                try {
                    resultSet.close();
                } catch (SQLException ignore) {
                }
            if (statement != null)
                try {
                    statement.close();
                } catch (SQLException ignore) {
                }
        }

        // let's return the conection
        CacheConnection.checkIn(connection);

        out.println("Hello " + userName + "!<p>");
        out.println("You're using a cached connection!<p>");
        out.println("</body>");
        out.println("</html>");
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        doGet(request, response);
    }
}

class CacheConnection {
    private static boolean verbose = false;

    private static int numberConnections = 0;

    private static Vector cachedConnections = new Vector();

    private static Thread monitor = null;

    private static long MAX_IDLE = 1000 * 60 * 60;

    synchronized public static Connection checkOut() {
        return checkOut("Database");
    }

    synchronized public static Connection checkOut(String baseName) {
        boolean found = false;
        CachedConnection cached = null;

        if (verbose) {
            System.out.println("There are " + Integer.toString(numberConnections) + " connections in the cache");
            System.out.println("Searching for a connection not in use...");
        }
        for (int i = 0; !found && i < numberConnections; i++) {
            if (verbose) {
                System.out.println("Vector entry " + Integer.toString(i));
            }
            cached = (CachedConnection) cachedConnections.get(i);
            if (!cached.isInUse() && cached.getBaseName().equals(baseName)) {
                if (verbose) {
                    System.out.println("found cached entry " + Integer.toString(i) + " for " + baseName);
                }
                found = true;
            }
        }
        if (found) {
            cached.setInUse(true);
        } else {
            if (verbose) {
                System.out.println("Cached entry not found ");
                System.out.println("Allocating new entry for " + baseName);
            }
            cached = new CachedConnection(Database.getConnection(baseName), true, baseName);
            cachedConnections.add(cached);
            numberConnections++;
        }

        if (monitor == null) {
            monitor = new Thread(new Runnable() {
                public void run() {
                    while (numberConnections > 0) {
                        runMonitor();
                    }
                    monitor = null;
                    if (verbose) {
                        System.out.println("CacheConnection monitor stopped");
                    }
                }
            });
            monitor.setDaemon(true);
            monitor.start();
        }
        return cached.getConnection();
    }

    synchronized public static void checkIn(Connection c) {
        boolean found = false;
        boolean closed = false;
        CachedConnection cached = null;
        Connection conn = null;
        int i = 0;

        if (verbose) {
            System.out.println("Searching for connection to set not in use...");
        }
        for (i = 0; !found && i < numberConnections; i++) {
            if (verbose) {
                System.out.println("Vector entry " + Integer.toString(i));
            }
            cached = (CachedConnection) cachedConnections.get(i);
            conn = cached.getConnection();
            if (conn == c) {
                if (verbose) {
                    System.out.println("found cached entry " + Integer.toString(i));
                }
                found = true;
            }
        }
        if (found) {
            try {
                closed = conn.isClosed();
            } catch (SQLException ignore) {
                closed = true;
            }
            if (!closed)
                cached.setInUse(false);
            else {
                cachedConnections.remove(i);
                numberConnections--;
            }
        } else if (verbose) {
            System.out.println("In use Connection not found!!!");
        }
    }

    synchronized private static void checkUse() {
        CachedConnection cached = null;
        Connection conn = null;
        int i = 0;
        long now = System.currentTimeMillis();
        long then = 0;

        for (i = numberConnections - 1; i > -1; i--) {
            if (verbose) {
                System.out.println(
                        "CacheConnection monitor checking vector entry " + Integer.toString(i) + " for use...");
            }
            cached = (CachedConnection) cachedConnections.get(i);
            if (!cached.isInUse()) {
                then = cached.getLastUsed();
                if ((now - then) > MAX_IDLE) {
                    if (verbose) {
                        System.out
                                .println("Cached entry " + Integer.toString(i) + " idle too long, being destroyed");
                    }
                    conn = cached.getConnection();
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        System.err.println("Unable to close connection: " + e.getMessage());
                    }
                    cachedConnections.remove(i);
                    numberConnections--;
                }
            }
        }
    }

    private static void runMonitor() {
        checkUse();
        if (numberConnections > 0) {
            if (verbose) {
                System.out.println("CacheConnection monitor going to sleep");
            }
            try {
                // 1000 milliseconds/second x 60 seconds/minute x 5 minutes
                monitor.sleep(1000 * 60 * 5);
            } catch (InterruptedException ignore) {
                if (verbose) {
                    System.out.println("CacheConnection monitor's sleep was interrupted");
                }
            }
        }
    }

    public void finalize() throws Throwable {
        CachedConnection cached = null;
        for (int i = 0; i < numberConnections; i++) {
            cached = (CachedConnection) cachedConnections.get(i);
            if (cached.getConnection() != null) {
                if (verbose) {
                    System.out.println("Closing connection on Vector entry " + Integer.toString(i));
                }
                try {
                    cached.getConnection().close();
                } catch (SQLException ignore) {
                    System.err.println("Can't close connection!!!");
                }
            }
        }
        numberConnections = 0;
    }

    public static void setVerbose(boolean v) {
        verbose = v;
    }
}

class CachedConnection {
    private boolean inUse;

    private Connection conn;

    private long lastUsed;

    private String baseName;

    public CachedConnection() {
        conn = null;
        inUse = false;
        lastUsed = System.currentTimeMillis();
        baseName = "Database";
    }

    public CachedConnection(Connection conn, boolean inUse) {
        this.conn = conn;
        this.inUse = inUse;
        this.lastUsed = System.currentTimeMillis();
        this.baseName = "Database";
    }

    public CachedConnection(Connection conn, boolean inUse, String baseName) {
        this.conn = conn;
        this.inUse = inUse;
        this.lastUsed = System.currentTimeMillis();
        this.baseName = baseName;
    }

    public Connection getConnection() {
        return conn;
    }

    public void setConnection(Connection conn) {
        this.conn = conn;
    }

    public boolean getInUse() {
        return inUse;
    }

    public boolean isInUse() {
        return inUse;
    }

    public void setInUse(boolean inUse) {
        if (!inUse)
            lastUsed = System.currentTimeMillis();
        this.inUse = inUse;
    }

    public String getBaseName() {
        return baseName;
    }

    public void setBaseName(String baseName) {
        this.baseName = baseName;
    }

    public long getLastUsed() {
        return lastUsed;
    }
}

class Database {
    private static boolean verbose = false;

    public static final Connection getConnection(String baseName) {
        Connection conn = null;
        String driver = null;
        String url = null;
        String username = null;
        String password = null;
        try {
            ResourceBundle resb = ResourceBundle.getBundle(baseName);
            driver = resb.getString("database.driver");
            url = resb.getString("database.url");
            username = resb.getString("database.username");
            password = resb.getString("database.password");
            Class.forName(driver);
        } catch (MissingResourceException e) {
            System.err.println("Missing Resource: " + e.getMessage());
            return conn;
        } catch (ClassNotFoundException e) {
            System.err.println("Class not found: " + e.getMessage());
            return conn;
        }
        try {
            if (verbose) {
                System.out.println("baseName=" + baseName);
                System.out.println("driver=" + driver);
                System.out.println("url=" + url);
                System.out.println("username=" + username);
                System.out.println("password=" + password);
            }

            conn = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            System.err.println(e.getMessage());
            System.err.println("in Database.getConnection");
            System.err.println("on getConnection");
            conn = null;
        } finally {
            return conn;
        }
    }

    public static void setVerbose(boolean v) {
        verbose = v;
    }
}