Java tutorial
/* * 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; } }