com.octo.captcha.engine.bufferedengine.buffer.DatabaseCaptchaBuffer.java Source code

Java tutorial

Introduction

Here is the source code for com.octo.captcha.engine.bufferedengine.buffer.DatabaseCaptchaBuffer.java

Source

/*
 * JCaptcha, the open source java framework for captcha definition and integration
 * Copyright (c)  2007 jcaptcha.net. All Rights Reserved.
 * See the LICENSE.txt file distributed with this package.
 */

/*
 * jcaptcha, the open source java framework for captcha definition and integration
 * copyright (c)  2007 jcaptcha.net. All Rights Reserved.
 * See the LICENSE.txt file distributed with this package.
 */

/*
 * jcaptcha, the open source java framework for captcha definition and integration
 * copyright (c)  2007 jcaptcha.net. All Rights Reserved.
 * See the LICENSE.txt file distributed with this package.
 */
package com.octo.captcha.engine.bufferedengine.buffer;

import com.octo.captcha.Captcha;
import org.apache.commons.collections.buffer.UnboundedFifoBuffer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.sql.DataSource;
import java.io.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

/**
 * A database Captcha Buffer.
 * <p/>
 * The database should have the following structure : default Column Name , type </p> <ul> <li> timemillis , long </li>
 * <li> hashCode , long </li> <li> locale , string </li> <li> captcha , object </li> </ul>
 *
 * @author <a href="mailto:marc.antoine.garrigue@gmail.com">Marc-Antoine Garrigue</a>
 * @version 1.0
 */
public class DatabaseCaptchaBuffer implements CaptchaBuffer {

    private static final Log log = LogFactory.getLog(DatabaseCaptchaBuffer.class.getName());

    //database attributes
    private DataSource datasource;
    private String table = "JCAPTCHA_T";
    private String timeMillisColumn = "timemillis";
    private String hashCodeColumn = "hashCode";
    private String localeColumn = "locale";
    private String captchaColumn = "captcha";
    private static final String DB_ERROR = "SQL Error :";

    public DatabaseCaptchaBuffer(DataSource datasource) {
        log.info("Initializing Buffer");
        this.datasource = datasource;
        log.info("Buffer size : " + size());
        log.info("Buffer initialized");
    }

    public DatabaseCaptchaBuffer(DataSource datasource, String table) {
        log.info("Initializing Buffer");
        this.datasource = datasource;
        this.table = table;
        log.info("Buffer size : " + size());
        log.info("Buffer initialized");
    }

    public DatabaseCaptchaBuffer(DataSource datasource, String table, String timeMillisColumn,
            String hashCodeColumn, String captchaColumn, String localeColumn) {
        log.info("Initializing Buffer");
        this.datasource = datasource;
        this.table = table;
        this.timeMillisColumn = timeMillisColumn;
        this.hashCodeColumn = hashCodeColumn;
        this.captchaColumn = captchaColumn;
        this.localeColumn = localeColumn;
        log.info("Buffer size : " + size());
        log.info("Buffer initialized");
    }

    //Buffer methods

    /**
     * remove a captcha from the buffer
     *
     * @return a captcha
     *
     * @throws java.util.NoSuchElementException
     *          if there is no captcha throw NoSuchElementException
     */
    public Captcha removeCaptcha() throws NoSuchElementException {
        return removeCaptcha(Locale.getDefault());
    }

    /**
     * remove a captcha from the buffer corresponding to the locale
     *
     * @param locale The locale the catcha to remove
     *
     * @return a captcha correponding to the locale
     *
     * @throws NoSuchElementException if there is no captcha throw NoSuchElementException
     */
    public Captcha removeCaptcha(Locale locale) throws NoSuchElementException {
        Collection col = removeCaptcha(1, locale);
        if (col != null && col.size() > 0) {
            return (Captcha) col.iterator().next();
        } else {
            throw new NoSuchElementException("no captcha in this buffer for locale " + locale);
        }
    }

    /**
     * Remove a precise number of captcha
     *
     * @param number The number of captchas to remove
     *
     * @return a collection of captchas
     */
    public Collection removeCaptcha(int number) {
        return removeCaptcha(number, Locale.getDefault());
    }

    /**
     * Remove a precise number of captcha with a locale
     *
     * @param number The number of captchas to remove
     * @param locale The locale of the removed captchas
     *
     * @return a collection of captchas
     */
    public Collection removeCaptcha(int number, Locale locale) {
        Connection con = null;
        PreparedStatement ps = null;
        PreparedStatement psdel = null;
        ResultSet rs = null;
        Collection collection = new UnboundedFifoBuffer();
        Collection temp = new UnboundedFifoBuffer();
        if (number < 1) {
            return collection;
        }
        try {
            if (log.isDebugEnabled()) {
                log.debug("try to remove " + number + " captchas");
            }
            ;
            con = datasource.getConnection();

            ps = con.prepareStatement(
                    "select *  from " + table + " where " + localeColumn + " = ? order by " + timeMillisColumn);

            psdel = con.prepareStatement(
                    "delete from " + table + " where " + timeMillisColumn + "= ? and " + hashCodeColumn + "= ? ");//and " + localeColumn
            //+ "= ?");
            ps.setString(1, locale.toString());
            ps.setMaxRows(number);
            //read
            rs = ps.executeQuery();
            int i = 0;
            while (rs.next() && i < number) {
                try {
                    i++;
                    InputStream in = rs.getBinaryStream(captchaColumn);
                    ObjectInputStream objstr = new ObjectInputStream(in);
                    Object captcha = objstr.readObject();
                    temp.add(captcha);
                    //and delete
                    long time = rs.getLong(timeMillisColumn);
                    long hash = rs.getLong(hashCodeColumn);
                    psdel.setLong(1, time);
                    psdel.setLong(2, hash);
                    //psdel.setString(3, rs.getString(localeColumn));
                    psdel.addBatch();

                    if (log.isDebugEnabled()) {
                        log.debug("remove captcha added to batch : " + time + ";" + hash);
                    }

                } catch (IOException e) {
                    log.error("error during captcha deserialization, "
                            + "check your class versions. removing row from database", e);
                    psdel.execute();
                } catch (ClassNotFoundException e) {
                    log.error("Serialized captcha class in database is not in your classpath!", e);
                }

            }
            //execute batch delete
            psdel.executeBatch();
            log.debug("batch executed");
            rs.close();
            //commit the whole stuff
            con.commit();
            log.debug("batch commited");
            //only add after commit
            collection.addAll(temp);
        } catch (SQLException e) {
            log.error(DB_ERROR, e);
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException ex) {
                }
            }

        } finally {

            if (ps != null) {
                try {
                    ps.close();
                } // rollback on error
                catch (SQLException e) {
                }
            }
            if (con != null) {
                try {
                    con.close();
                } // rollback on error
                catch (SQLException e) {
                }
            }
        }
        return collection;
    }

    /**
     * Put a captcha with default locale
     */
    public void putCaptcha(Captcha captcha) {
        putCaptcha(captcha, Locale.getDefault());
    }

    /**
     * Put a captcha with a locale
     *
     * @param captcha The captcha to add
     * @param locale  the locale of the captcha
     */
    public void putCaptcha(Captcha captcha, Locale locale) {
        if (captcha != null) {
            Set set = new HashSet();
            set.add(captcha);
            putAllCaptcha(set, locale);
        }
    }

    /**
     * Put a collection of captchas with the default locale
     *
     * @param captchas The captchas to add
     */
    public void putAllCaptcha(Collection captchas) {
        putAllCaptcha(captchas, Locale.getDefault());
    }

    /**
     * Put a collection of captchas with his locale
     *
     * @param captchas The captchas to add
     * @param locale   The locale of the captchas
     */
    public void putAllCaptcha(Collection captchas, Locale locale) {
        Connection con = null;
        PreparedStatement ps = null;

        if (captchas != null && captchas.size() > 0) {
            Iterator captIt = captchas.iterator();
            if (log.isDebugEnabled()) {
                log.debug("try to insert " + captchas.size() + " captchas");
            }

            try {
                con = datasource.getConnection();
                con.setAutoCommit(false);
                ps = con.prepareStatement("insert into " + table + "(" + timeMillisColumn + "," + hashCodeColumn
                        + "," + localeColumn + "," + captchaColumn + ") values (?,?,?,?)");

                while (captIt.hasNext()) {

                    Captcha captcha = (Captcha) captIt.next();
                    try {
                        long currenttime = System.currentTimeMillis();
                        long hash = captcha.hashCode();

                        ps.setLong(1, currenttime);
                        ps.setLong(2, hash);
                        ps.setString(3, locale.toString());
                        // Serialise the entry
                        final ByteArrayOutputStream outstr = new ByteArrayOutputStream();
                        final ObjectOutputStream objstr = new ObjectOutputStream(outstr);
                        objstr.writeObject(captcha);
                        objstr.close();
                        final ByteArrayInputStream inpstream = new ByteArrayInputStream(outstr.toByteArray());

                        ps.setBinaryStream(4, inpstream, outstr.size());

                        ps.addBatch();

                        if (log.isDebugEnabled()) {
                            log.debug("insert captcha added to batch : " + currenttime + ";" + hash);
                        }

                    } catch (IOException e) {
                        log.warn("error during captcha serialization, "
                                + "check your class versions. removing row from database", e);
                    }
                }
                //exexute batch and commit()

                ps.executeBatch();
                log.debug("batch executed");

                con.commit();
                log.debug("batch commited");

            } catch (SQLException e) {
                log.error(DB_ERROR, e);

            } finally {
                if (ps != null) {
                    try {
                        ps.close();
                    } catch (SQLException e) {
                    }
                }
                if (con != null) {
                    try {
                        con.close();
                    } catch (SQLException e) {
                    }
                }
            }
        }

    }

    /**
     * Get the size of the buffer for all locales
     *
     * @return The size of the buffer
     */
    public int size() {
        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        int size = 0;

        try {
            con = datasource.getConnection();
            ps = con.prepareStatement("select count(*) from " + table);
            rs = ps.executeQuery();
            if (rs.next()) {
                size = rs.getInt(1);
            }
            rs.close();
            con.commit();
        } catch (SQLException e) {
            log.error(DB_ERROR, e);
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException ex) {
                }
            }
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                }
            }
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                }
            }
        }

        return size;

    }

    /**
     * Get the size of the buffer for a locale
     *
     * @param locale the locale to get the size
     *
     * @return The size of the buffer
     */
    public int size(Locale locale) {
        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        int size = 0;

        try {
            con = datasource.getConnection();
            ps = con.prepareStatement("select count(*) from " + table + " where " + localeColumn + "=?");
            ps.setString(1, locale.toString());
            rs = ps.executeQuery();
            if (rs.next()) {
                size = rs.getInt(1);
            }
            rs.close();
            con.commit();
        } catch (SQLException e) {
            log.error(DB_ERROR, e);
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException ex) {
                }
            }
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                }
            }
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                }
            }
        }

        return size;
    }

    /**
     * Release all the ressources and close the buffer.
     */
    public void dispose() {
    }

    /**
     * Clear the buffer from all locale
     */
    public void clear() {
        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            con = datasource.getConnection();
            ps = con.prepareStatement("delete from " + table);
            ps.execute();
            con.commit();

        } catch (SQLException e) {
            log.error(DB_ERROR, e);
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException ex) {
                }
            }
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                }
            }
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                }
            }
        }

    }

    /**
     * Get all the locales used
     */
    public Collection getLocales() {
        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        Set set = new HashSet();

        try {
            con = datasource.getConnection();
            ps = con.prepareStatement("select distinct " + localeColumn + " from " + table);
            rs = ps.executeQuery();
            while (rs.next()) {
                set.add(rs.getString(1));
            }
            rs.close();
            con.commit();
        } catch (SQLException e) {
            log.error(DB_ERROR, e);
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException ex) {
                }
            }
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                }
            }
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                }
            }
        }

        return set;
    }

}