FileDocCategorySizeDatePackage
JDBCBayesianAnalyzer.javaAPI DocApache James 2.3.113962Fri Jan 12 12:56:34 GMT 2007org.apache.james.util

JDBCBayesianAnalyzer

public abstract class JDBCBayesianAnalyzer extends BayesianAnalyzer
Manages the persistence of the spam bayesian analysis corpus using a JDBC database.

This class is abstract to allow implementations to take advantage of different logging capabilities/interfaces in different parts of the code.

version
CVS $Revision: $ $Date: $
since
2.3.0

Fields Summary
public static final String
DATABASE_LOCK
Public object representing a lock on database activity.
private final JDBCUtil
theJDBCUtil
The JDBCUtil helper class
private SqlResources
sqlQueries
Contains all of the sql strings for this component.
private String
sqlFileName
Holds value of property sqlFileName.
private File
sqlFile
private Map
sqlParameters
Holds value of property sqlParameters.
private static long
lastDatabaseUpdateTime
Holds value of property lastDatabaseUpdateTime.
Constructors Summary
public JDBCBayesianAnalyzer()
Default constructor.

    
Methods Summary
private voidcheckTables(java.sql.Connection conn)

        DatabaseMetaData dbMetaData = conn.getMetaData();
        // Need to ask in the case that identifiers are stored, ask the DatabaseMetaInfo.
        // Try UPPER, lower, and MixedCase, to see if the table is there.
        
        boolean dbUpdated = false;
        
        dbUpdated = createTable(conn, "hamTableName", "createHamTable");
        
        dbUpdated = createTable(conn, "spamTableName", "createSpamTable");
        
        dbUpdated = createTable(conn, "messageCountsTableName", "createMessageCountsTable");
        
        //Commit our changes if necessary.
        if (conn != null && dbUpdated && !conn.getAutoCommit()) {
            conn.commit();
            dbUpdated = false;
        }
            
    
private booleancreateTable(java.sql.Connection conn, java.lang.String tableNameSqlStringName, java.lang.String createSqlStringName)

        String tableName = sqlQueries.getSqlString(tableNameSqlStringName, true);
        
        DatabaseMetaData dbMetaData = conn.getMetaData();

        // Try UPPER, lower, and MixedCase, to see if the table is there.
        if (theJDBCUtil.tableExists(dbMetaData, tableName)) {
            return false;
        }
        
        PreparedStatement createStatement = null;
        
        try {
            createStatement =
                    conn.prepareStatement(sqlQueries.getSqlString(createSqlStringName, true));
            createStatement.execute();
            
            StringBuffer logBuffer = null;
            logBuffer =
                    new StringBuffer(64)
                    .append("Created table '")
                    .append(tableName)
                    .append("' using sqlResources string '")
                    .append(createSqlStringName)
                    .append("'.");
            delegatedLog(logBuffer.toString());
            
        } finally {
            theJDBCUtil.closeJDBCStatement(createStatement);
        }
        
        return true;
    
protected abstract voiddelegatedLog(java.lang.String errorString)
An abstract method which child classes override to handle logging of errors in their particular environments.

param
errorString the error message generated

public static longgetLastDatabaseUpdateTime()
Getter for static lastDatabaseUpdateTime.

return
Value of property lastDatabaseUpdateTime.


        return lastDatabaseUpdateTime;
    
public java.lang.StringgetSqlFileName()
Getter for property sqlFileName.

return
Value of property sqlFileName.

    
                  
       

        return this.sqlFileName;
    
public java.util.MapgetSqlParameters()
Getter for property sqlParameters.

return
Value of property sqlParameters.


        return this.sqlParameters;
    
public voidinitSqlQueries(java.sql.Connection conn, org.apache.mailet.MailetContext mailetContext)
Initializes the sql query environment from the SqlResources file. Will look for conf/sqlResources.xml.

param
conn The connection for accessing the database
param
mailetContext The current mailet context, for finding the conf/sqlResources.xml file
throws
Exception If any error occurs

        try {
            if (conn.getAutoCommit()) {
                conn.setAutoCommit(false);
            }
            
            this.sqlFile = new File((String) mailetContext.getAttribute("confDir"), "sqlResources.xml").getCanonicalFile();
            sqlQueries.init(this.sqlFile, JDBCBayesianAnalyzer.class.getName() , conn, getSqlParameters());
            
            checkTables(conn);
        } finally {
            theJDBCUtil.closeJDBCConnection(conn);
        }
    
public voidloadHamNSpam(java.sql.Connection conn)
Loads the token frequencies from the database.

param
conn The connection for accessing the database
throws
SQLException If a database error occurs

        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            pstmt = conn.prepareStatement(sqlQueries.getSqlString("selectHamTokens", true));
            rs = pstmt.executeQuery();
            
            Map ham = getHamTokenCounts();
            while (rs.next()) {
                String token = rs.getString(1);
                int count = rs.getInt(2);
                // to reduce memory, use the token only if the count is > 1
                if (count > 1) {
                    ham.put(token, new Integer(count));
                }
            }
            //Verbose.
            delegatedLog("Ham tokens count: " + ham.size());
            
            rs.close();
            pstmt.close();
                        
            //Get the spam tokens/counts.
            pstmt = conn.prepareStatement(sqlQueries.getSqlString("selectSpamTokens", true));
            rs = pstmt.executeQuery();
            
            Map spam = getSpamTokenCounts();
            while (rs.next()) {
                String token = rs.getString(1);
                int count = rs.getInt(2);
                // to reduce memory, use the token only if the count is > 1
                if (count > 1) {
                    spam.put(token, new Integer(count));
                }
            }
            
            //Verbose.
            delegatedLog("Spam tokens count: " + spam.size());
            
            rs.close();
            pstmt.close();
                        
            //Get the ham/spam message counts.
            pstmt = conn.prepareStatement(sqlQueries.getSqlString("selectMessageCounts", true));
            rs = pstmt.executeQuery();
            if (rs.next()) {
                setHamMessageCount(rs.getInt(1));
                setSpamMessageCount(rs.getInt(2));
            }
            
            rs.close();
            pstmt.close();
            
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (java.sql.SQLException se) {
                }
                
                rs = null;
            }
            
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (java.sql.SQLException se) {
                }
                
                pstmt = null;
            }
        }
    
private voidsetMessageCount(java.sql.Connection conn, java.lang.String sqlStatement, int count)

        PreparedStatement init = null;
        PreparedStatement update = null;
        
        try {
            //set the ham/spam message counts.
            init = conn.prepareStatement(sqlQueries.getSqlString("initializeMessageCounts", true));
            update = conn.prepareStatement(sqlStatement);
            
            update.setInt(1, count);
            
            if (update.executeUpdate() == 0) {
                init.executeUpdate();
                update.executeUpdate();
            }

        } finally {
            if (init != null) {
                try {
                    init.close();
                } catch (java.sql.SQLException ignore) {
                }
            }
            if (update != null) {
                try {
                    update.close();
                } catch (java.sql.SQLException ignore) {
                }
            }
        }
    
public voidsetSqlFileName(java.lang.String sqlFileName)
Setter for property sqlFileName.

param
sqlFileName New value of property sqlFileName.


        this.sqlFileName = sqlFileName;
    
public voidsetSqlParameters(java.util.Map sqlParameters)
Setter for property sqlParameters.

param
sqlParameters New value of property sqlParameters.


        this.sqlParameters = sqlParameters;
    
public static voidtouchLastDatabaseUpdateTime()
Sets static lastDatabaseUpdateTime to System.currentTimeMillis().


        lastDatabaseUpdateTime = System.currentTimeMillis();
    
public voidupdateHamTokens(java.sql.Connection conn)
Updates the database with new "ham" token frequencies.

param
conn The connection for accessing the database
throws
SQLException If a database error occurs

        updateTokens(conn, getHamTokenCounts(),
                sqlQueries.getSqlString("insertHamToken", true),
                sqlQueries.getSqlString("updateHamToken", true));
        
        setMessageCount(conn, sqlQueries.getSqlString("updateHamMessageCounts", true), getHamMessageCount());
    
public voidupdateSpamTokens(java.sql.Connection conn)
Updates the database with new "spam" token frequencies.

param
conn The connection for accessing the database
throws
SQLException If a database error occurs

         updateTokens(conn, getSpamTokenCounts(),
                sqlQueries.getSqlString("insertSpamToken", true),
                sqlQueries.getSqlString("updateSpamToken", true));
       
        setMessageCount(conn, sqlQueries.getSqlString("updateSpamMessageCounts", true), getSpamMessageCount());
    
private voidupdateTokens(java.sql.Connection conn, java.util.Map tokens, java.lang.String insertSqlStatement, java.lang.String updateSqlStatement)

        PreparedStatement insert = null;
        PreparedStatement update = null;
        
        try {
            //Used to insert new token entries.
            insert = conn.prepareStatement(insertSqlStatement);
            
            //Used to update existing token entries.
            update = conn.prepareStatement(updateSqlStatement);
            
            Iterator i = tokens.keySet().iterator();
            while (i.hasNext()) {
                String key = (String) i.next();
                int value = ((Integer) tokens.get(key)).intValue();
                
                update.setInt(1, value);
                update.setString(2, key);
                
                //If the update affected 0 (zero) rows, then the token hasn't been
                //encountered before, and we need to add it to the corpus.
                if (update.executeUpdate() == 0) {
                    insert.setString(1, key);
                    insert.setInt(2, value);
                    
                    insert.executeUpdate();
                }
            }
        } finally {
            if (insert != null) {
                try {
                    insert.close();
                } catch (java.sql.SQLException ignore) {
                }
                
                insert = null;
            }
            
            if (update != null) {
                try {
                    update.close();
                } catch (java.sql.SQLException ignore) {
                }
                
                update = null;
            }
        }