FileDocCategorySizeDatePackage
JDBCStore.javaAPI DocApache Tomcat 6.0.1433084Fri Jul 20 04:20:36 BST 2007org.apache.catalina.session

JDBCStore

public class JDBCStore extends StoreBase implements org.apache.catalina.Store
Implementation of the Store interface that stores serialized session objects in a database. Sessions that are saved are still subject to being expired based on inactivity.
author
Bip Thelin
version
$Revision: 554109 $, $Date: 2007-07-07 03:40:19 +0200 (sam., 07 juil. 2007) $

Fields Summary
protected static String
info
The descriptive information about this implementation.
private String
name
Context name associated with this Store
protected static String
storeName
Name to register for this Store, used for logging.
protected String
threadName
Name to register for the background thread.
protected String
connectionName
The connection username to use when trying to connect to the database.
protected String
connectionPassword
The connection URL to use when trying to connect to the database.
protected String
connectionURL
Connection string to use when connecting to the DB.
private Connection
dbConnection
The database connection.
protected Driver
driver
Instance of the JDBC Driver class we use as a connection factory.
protected String
driverName
Driver to use.
protected String
sessionTable
Table to use.
protected String
sessionAppCol
Column to use for /Engine/Host/Context name
protected String
sessionIdCol
Id column to use.
protected String
sessionDataCol
Data column to use.
protected String
sessionValidCol
Is Valid column to use.
protected String
sessionMaxInactiveCol
Max Inactive column to use.
protected String
sessionLastAccessedCol
Last Accessed column to use.
protected PreparedStatement
preparedSizeSql
Variable to hold the getSize() prepared statement.
protected PreparedStatement
preparedKeysSql
Variable to hold the keys() prepared statement.
protected PreparedStatement
preparedSaveSql
Variable to hold the save() prepared statement.
protected PreparedStatement
preparedClearSql
Variable to hold the clear() prepared statement.
protected PreparedStatement
preparedRemoveSql
Variable to hold the remove() prepared statement.
protected PreparedStatement
preparedLoadSql
Variable to hold the load() prepared statement.
Constructors Summary
Methods Summary
public voidclear()
Remove all of the Sessions in this Store.

exception
IOException if an input/output error occurs


        synchronized (this) {
            int numberOfTries = 2;
            while (numberOfTries > 0) {
                Connection _conn = getConnection();
                if (_conn == null) {
                    return;
                }

                try {
                    if (preparedClearSql == null) {
                        String clearSql = "DELETE FROM " + sessionTable
                             + " WHERE " + sessionAppCol + " = ?";
                        preparedClearSql = _conn.prepareStatement(clearSql);
                    }

                    preparedClearSql.setString(1, getName());
                    preparedClearSql.execute();
                    // Break out after the finally block
                    numberOfTries = 0;
                } catch (SQLException e) {
                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
                    if (dbConnection != null)
                        close(dbConnection);
                } finally {
                    release(_conn);
                }
                numberOfTries--;
            }
        }
    
protected voidclose(java.sql.Connection dbConnection)
Close the specified database connection.

param
dbConnection The connection to be closed


        // Do nothing if the database connection is already closed
        if (dbConnection == null)
            return;

        // Close our prepared statements (if any)
        try {
            preparedSizeSql.close();
        } catch (Throwable f) {
            ;
        }
        this.preparedSizeSql = null;

        try {
            preparedKeysSql.close();
        } catch (Throwable f) {
            ;
        }
        this.preparedKeysSql = null;

        try {
            preparedSaveSql.close();
        } catch (Throwable f) {
            ;
        }
        this.preparedSaveSql = null;

        try {
            preparedClearSql.close();
        } catch (Throwable f) {
            ;
        }
         
		try {
            preparedRemoveSql.close();
        } catch (Throwable f) {
            ;
        }
        this.preparedRemoveSql = null;

        try {
            preparedLoadSql.close();
        } catch (Throwable f) {
            ;
        }
        this.preparedLoadSql = null;

        // Close this database connection, and log any errors
        try {
            dbConnection.close();
        } catch (SQLException e) {
            manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".close", e.toString())); // Just log it here
        } finally {
            this.dbConnection = null;
        }

    
protected java.sql.ConnectiongetConnection()
Check the connection associated with this store, if it's null or closed try to reopen it. Returns null if the connection could not be established.

return
Connection if the connection suceeded

        try {
            if (dbConnection == null || dbConnection.isClosed()) {
                manager.getContainer().getLogger().info(sm.getString(getStoreName() + ".checkConnectionDBClosed"));
                open();
                if (dbConnection == null || dbConnection.isClosed()) {
                    manager.getContainer().getLogger().info(sm.getString(getStoreName() + ".checkConnectionDBReOpenFail"));
                }
            }
        } catch (SQLException ex) {
            manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionSQLException",
                    ex.toString()));
        }

        return dbConnection;
    
public java.lang.StringgetConnectionName()
Return the username to use to connect to the database.

        return connectionName;
    
public java.lang.StringgetConnectionPassword()
Return the password to use to connect to the database.

        return connectionPassword;
    
public java.lang.StringgetConnectionURL()
Return the Connection URL for this Store.

        return (this.connectionURL);
    
public java.lang.StringgetDriverName()
Return the driver for this Store.

        return (this.driverName);
    
public java.lang.StringgetInfo()
Return the info for this Store.


    // ------------------------------------------------------------- Properties

               
       
        return (info);
    
public java.lang.StringgetName()
Return the name for this instance (built from container name)

        if (name == null) {
            Container container = manager.getContainer();
            String contextName = container.getName();
            String hostName = "";
            String engineName = "";

            if (container.getParent() != null) {
                Container host = container.getParent();
                hostName = host.getName();
                if (host.getParent() != null) {
                    engineName = host.getParent().getName();
                }
            }
            name = "/" + engineName + "/" + hostName + contextName;
        }
        return name;
    
public java.lang.StringgetSessionAppCol()
Return the web application name column for the table.

        return (this.sessionAppCol);
    
public java.lang.StringgetSessionDataCol()
Return the data column for the table

        return (this.sessionDataCol);
    
public java.lang.StringgetSessionIdCol()
Return the Id column for the table.

        return (this.sessionIdCol);
    
public java.lang.StringgetSessionLastAccessedCol()
Return the Last Accessed column

        return (this.sessionLastAccessedCol);
    
public java.lang.StringgetSessionMaxInactiveCol()
Return the Max Inactive column

        return (this.sessionMaxInactiveCol);
    
public java.lang.StringgetSessionTable()
Return the table for this Store.

        return (this.sessionTable);
    
public java.lang.StringgetSessionValidCol()
Return the Is Valid column

        return (this.sessionValidCol);
    
public intgetSize()
Return an integer containing a count of all Sessions currently saved in this Store. If there are no Sessions, 0 is returned.

exception
IOException if an input/output error occurred

        int size = 0;
        ResultSet rst = null;

        synchronized (this) {
            int numberOfTries = 2;
            while (numberOfTries > 0) {
                Connection _conn = getConnection();

                if (_conn == null) {
                    return (size);
                }

                try {
                    if (preparedSizeSql == null) {
                        String sizeSql = "SELECT COUNT(" + sessionIdCol
                                + ") FROM " + sessionTable + " WHERE "
                                + sessionAppCol + " = ?";
                        preparedSizeSql = _conn.prepareStatement(sizeSql);
					}

                    preparedSizeSql.setString(1, getName());
                    rst = preparedSizeSql.executeQuery();
                    if (rst.next()) {
                        size = rst.getInt(1);
                    }
                    // Break out after the finally block
                    numberOfTries = 0;
                } catch (SQLException e) {
                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
                    if (dbConnection != null)
                        close(dbConnection);
                } finally {
                    try {
                        if (rst != null)
                            rst.close();
                    } catch (SQLException e) {
                        ;
                    }

                    release(_conn);
                }
                numberOfTries--;
            }
        }
        return (size);
    
public java.lang.StringgetStoreName()
Return the name for this Store, used for logging.

        return (storeName);
    
public java.lang.StringgetThreadName()
Return the thread name for this Store.

        return (threadName);
    
public java.lang.String[]keys()
Return an array containing the session identifiers of all Sessions currently saved in this Store. If there are no such Sessions, a zero-length array is returned.

exception
IOException if an input/output error occurred

        ResultSet rst = null;
        String keys[] = null;
        synchronized (this) {
            int numberOfTries = 2;
            while (numberOfTries > 0) {

                Connection _conn = getConnection();
                if (_conn == null) {
                    return (new String[0]);
                }
                try {
                    if (preparedKeysSql == null) {
                        String keysSql = "SELECT " + sessionIdCol + " FROM "
                                + sessionTable + " WHERE " + sessionAppCol
                                + " = ?";
                        preparedKeysSql = _conn.prepareStatement(keysSql);
					}

                    preparedKeysSql.setString(1, getName());
                    rst = preparedKeysSql.executeQuery();
                    ArrayList tmpkeys = new ArrayList();
                    if (rst != null) {
                        while (rst.next()) {
                            tmpkeys.add(rst.getString(1));
                        }
                    }
                    keys = (String[]) tmpkeys.toArray(new String[tmpkeys.size()]);
                    // Break out after the finally block
                    numberOfTries = 0;
                } catch (SQLException e) {
                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
                    keys = new String[0];
                    // Close the connection so that it gets reopened next time
                    if (dbConnection != null)
                        close(dbConnection);
                } finally {
                    try {
                        if (rst != null) {
                            rst.close();
                        }
                    } catch (SQLException e) {
                        ;
                    }

                    release(_conn);
                }
                numberOfTries--;
            }
        }

        return (keys);
    
public org.apache.catalina.Sessionload(java.lang.String id)
Load the Session associated with the id id. If no such session is found null is returned.

param
id a value of type String
return
the stored Session
exception
ClassNotFoundException if an error occurs
exception
IOException if an input/output error occurred

        ResultSet rst = null;
        StandardSession _session = null;
        Loader loader = null;
        ClassLoader classLoader = null;
        ObjectInputStream ois = null;
        BufferedInputStream bis = null;
        Container container = manager.getContainer();
 
        synchronized (this) {
            int numberOfTries = 2;
            while (numberOfTries > 0) {
                Connection _conn = getConnection();
                if (_conn == null) {
                    return (null);
                }

                try {
                    if (preparedLoadSql == null) {
                        String loadSql = "SELECT " + sessionIdCol + ", "
                                + sessionDataCol + " FROM " + sessionTable
                                + " WHERE " + sessionIdCol + " = ? AND "
                                + sessionAppCol + " = ?";
                        preparedLoadSql = _conn.prepareStatement(loadSql);
                    }

                    preparedLoadSql.setString(1, id);
                    preparedLoadSql.setString(2, getName());
                    rst = preparedLoadSql.executeQuery();
                    if (rst.next()) {
                        bis = new BufferedInputStream(rst.getBinaryStream(2));

                        if (container != null) {
                            loader = container.getLoader();
                        }
                        if (loader != null) {
                            classLoader = loader.getClassLoader();
                        }
                        if (classLoader != null) {
                            ois = new CustomObjectInputStream(bis,
                                    classLoader);
                        } else {
                            ois = new ObjectInputStream(bis);
                        }

                        if (manager.getContainer().getLogger().isDebugEnabled()) {
                            manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".loading",
                                    id, sessionTable));
                        }

                        _session = (StandardSession) manager.createEmptySession();
                        _session.readObjectData(ois);
                        _session.setManager(manager);
                      } else if (manager.getContainer().getLogger().isDebugEnabled()) {
                        manager.getContainer().getLogger().debug(getStoreName() + ": No persisted data object found");
                    }
                    // Break out after the finally block
                    numberOfTries = 0;
                } catch (SQLException e) {
                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
                    if (dbConnection != null)
                        close(dbConnection);
                } finally {
                    try {
                        if (rst != null) {
                            rst.close();
                        }
                    } catch (SQLException e) {
                        ;
                    }
                    if (ois != null) {
                        try {
                            ois.close();
                        } catch (IOException e) {
                            ;
                        }
                    }
                    release(_conn);
                }
                numberOfTries--;
            }
        }

        return (_session);
    
protected java.sql.Connectionopen()
Open (if necessary) and return a database connection for use by this Realm.

exception
SQLException if a database error occurs


        // Do nothing if there is a database connection already open
        if (dbConnection != null)
            return (dbConnection);

        // Instantiate our database driver if necessary
        if (driver == null) {
            try {
                Class clazz = Class.forName(driverName);
                driver = (Driver) clazz.newInstance();
            } catch (ClassNotFoundException ex) {
                manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException",
                        ex.toString()));
            } catch (InstantiationException ex) {
                manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException",
                        ex.toString()));
            } catch (IllegalAccessException ex) {
                manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException",
                        ex.toString()));
            }
        }

        // Open a new connection
        Properties props = new Properties();
        if (connectionName != null)
            props.put("user", connectionName);
        if (connectionPassword != null)
            props.put("password", connectionPassword);
        dbConnection = driver.connect(connectionURL, props);
        dbConnection.setAutoCommit(true);
        return (dbConnection);

    
protected voidrelease(java.sql.Connection conn)
Release the connection, not needed here since the connection is not associated with a connection pool.

param
conn The connection to be released

        ;
    
public voidremove(java.lang.String id)
Remove the Session with the specified session identifier from this Store, if present. If no such Session is present, this method takes no action.

param
id Session identifier of the Session to be removed
exception
IOException if an input/output error occurs


        synchronized (this) {
            int numberOfTries = 2;
            while (numberOfTries > 0) {
                Connection _conn = getConnection();

                if (_conn == null) {
                    return;
                }

                try {
                    if (preparedRemoveSql == null) {
                        String removeSql = "DELETE FROM " + sessionTable
                                + " WHERE " + sessionIdCol + " = ?  AND "
                                + sessionAppCol + " = ?";
                        preparedRemoveSql = _conn.prepareStatement(removeSql);
                    }

                    preparedRemoveSql.setString(1, id);
                    preparedRemoveSql.setString(2, getName());
                    preparedRemoveSql.execute();
                    // Break out after the finally block
                    numberOfTries = 0;
                } catch (SQLException e) {
                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
                    if (dbConnection != null)
                        close(dbConnection);
                } finally {
                    release(_conn);
                }
                numberOfTries--;
            }
        }

        if (manager.getContainer().getLogger().isDebugEnabled()) {
            manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".removing", id, sessionTable));
        }
    
public voidsave(org.apache.catalina.Session session)
Save a session to the Store.

param
session the session to be stored
exception
IOException if an input/output error occurs

        ObjectOutputStream oos = null;
        ByteArrayOutputStream bos = null;
        ByteArrayInputStream bis = null;
        InputStream in = null;

        synchronized (this) {
            int numberOfTries = 2;
            while (numberOfTries > 0) {
                Connection _conn = getConnection();
                if (_conn == null) {
                    return;
                }

                // If sessions already exist in DB, remove and insert again.
                // TODO:
                // * Check if ID exists in database and if so use UPDATE.
                remove(session.getIdInternal());

                try {
                    bos = new ByteArrayOutputStream();
                    oos = new ObjectOutputStream(new BufferedOutputStream(bos));

                    ((StandardSession) session).writeObjectData(oos);
                    oos.close();
                    oos = null;
                    byte[] obs = bos.toByteArray();
                    int size = obs.length;
                    bis = new ByteArrayInputStream(obs, 0, size);
                    in = new BufferedInputStream(bis, size);

                    if (preparedSaveSql == null) {
                        String saveSql = "INSERT INTO " + sessionTable + " ("
                           + sessionIdCol + ", " + sessionAppCol + ", "
                           + sessionDataCol + ", " + sessionValidCol
                           + ", " + sessionMaxInactiveCol + ", "
                           + sessionLastAccessedCol
                           + ") VALUES (?, ?, ?, ?, ?, ?)";
                       preparedSaveSql = _conn.prepareStatement(saveSql);
					}

                    preparedSaveSql.setString(1, session.getIdInternal());
                    preparedSaveSql.setString(2, getName());
                    preparedSaveSql.setBinaryStream(3, in, size);
                    preparedSaveSql.setString(4, session.isValid() ? "1" : "0");
                    preparedSaveSql.setInt(5, session.getMaxInactiveInterval());
                    preparedSaveSql.setLong(6, session.getLastAccessedTime());
                    preparedSaveSql.execute();
                    // Break out after the finally block
                    numberOfTries = 0;
                } catch (SQLException e) {
                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
                    if (dbConnection != null)
                        close(dbConnection);
                } catch (IOException e) {
                    ;
                } finally {
                    if (oos != null) {
                        oos.close();
                    }
                    if (bis != null) {
                        bis.close();
                    }
                    if (in != null) {
                        in.close();
                    }

                    release(_conn);
                }
                numberOfTries--;
            }
        }

        if (manager.getContainer().getLogger().isDebugEnabled()) {
            manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".saving",
                    session.getIdInternal(), sessionTable));
        }
    
public voidsetConnectionName(java.lang.String connectionName)
Set the username to use to connect to the database.

param
connectionName Username

        this.connectionName = connectionName;
    
public voidsetConnectionPassword(java.lang.String connectionPassword)
Set the password to use to connect to the database.

param
connectionPassword User password

        this.connectionPassword = connectionPassword;
    
public voidsetConnectionURL(java.lang.String connectionURL)
Set the Connection URL for this Store.

param
connectionURL The new Connection URL

        String oldConnString = this.connectionURL;
        this.connectionURL = connectionURL;
        support.firePropertyChange("connectionURL",
                oldConnString,
                this.connectionURL);
    
public voidsetDriverName(java.lang.String driverName)
Set the driver for this Store.

param
driverName The new driver

        String oldDriverName = this.driverName;
        this.driverName = driverName;
        support.firePropertyChange("driverName",
                oldDriverName,
                this.driverName);
        this.driverName = driverName;
    
public voidsetSessionAppCol(java.lang.String sessionAppCol)
Set the App column for the table.

param
sessionAppCol the column name

        String oldSessionAppCol = this.sessionAppCol;
        this.sessionAppCol = sessionAppCol;
        support.firePropertyChange("sessionAppCol",
                oldSessionAppCol,
                this.sessionAppCol);
    
public voidsetSessionDataCol(java.lang.String sessionDataCol)
Set the Data column for the table

param
sessionDataCol the column name

        String oldSessionDataCol = this.sessionDataCol;
        this.sessionDataCol = sessionDataCol;
        support.firePropertyChange("sessionDataCol",
                oldSessionDataCol,
                this.sessionDataCol);
    
public voidsetSessionIdCol(java.lang.String sessionIdCol)
Set the Id column for the table.

param
sessionIdCol the column name

        String oldSessionIdCol = this.sessionIdCol;
        this.sessionIdCol = sessionIdCol;
        support.firePropertyChange("sessionIdCol",
                oldSessionIdCol,
                this.sessionIdCol);
    
public voidsetSessionLastAccessedCol(java.lang.String sessionLastAccessedCol)
Set the Last Accessed column for the table

param
sessionLastAccessedCol The column name

        String oldSessionLastAccessedCol = this.sessionLastAccessedCol;
        this.sessionLastAccessedCol = sessionLastAccessedCol;
        support.firePropertyChange("sessionLastAccessedCol",
                oldSessionLastAccessedCol,
                this.sessionLastAccessedCol);
    
public voidsetSessionMaxInactiveCol(java.lang.String sessionMaxInactiveCol)
Set the Max Inactive column for the table

param
sessionMaxInactiveCol The column name

        String oldSessionMaxInactiveCol = this.sessionMaxInactiveCol;
        this.sessionMaxInactiveCol = sessionMaxInactiveCol;
        support.firePropertyChange("sessionMaxInactiveCol",
                oldSessionMaxInactiveCol,
                this.sessionMaxInactiveCol);
    
public voidsetSessionTable(java.lang.String sessionTable)
Set the table for this Store.

param
sessionTable The new table

        String oldSessionTable = this.sessionTable;
        this.sessionTable = sessionTable;
        support.firePropertyChange("sessionTable",
                oldSessionTable,
                this.sessionTable);
    
public voidsetSessionValidCol(java.lang.String sessionValidCol)
Set the Is Valid column for the table

param
sessionValidCol The column name

        String oldSessionValidCol = this.sessionValidCol;
        this.sessionValidCol = sessionValidCol;
        support.firePropertyChange("sessionValidCol",
                oldSessionValidCol,
                this.sessionValidCol);
    
public voidstart()
Called once when this Store is first started.

        super.start();

        // Open connection to the database
        this.dbConnection = getConnection();
    
public voidstop()
Gracefully terminate everything associated with our db. Called once when this Store is stopping.

        super.stop();

        // Close and release everything associated with our db.
        if (dbConnection != null) {
            try {
                dbConnection.commit();
            } catch (SQLException e) {
                ;
            }
            close(dbConnection);
        }