package com.quickserverlab.quickcached.cache.impl.h2database; import java.sql.Connection; import java.util.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; import org.h2.jdbcx.JdbcConnectionPool; import com.quickserverlab.quickcached.QuickCached; import com.quickserverlab.quickcached.cache.impl.BaseCacheImpl; /** * H2 based implementation * @author Ifteqar Ahmed * @author Akshathkumar Shetty */ public class H2CacheImpl extends BaseCacheImpl { private static final Logger logger = Logger.getLogger(H2CacheImpl.class.getName()); private static JdbcConnectionPool cp = JdbcConnectionPool.create("jdbc:h2:mem:test", "sa", "sa"); static { createTable(); } public static Connection getConnection() throws SQLException { return cp.getConnection(); } public String getName() { return "H2CacheImpl"; } public long getSize() { return -1; } public void setToCache(String key, Object value, int objectSize, int expInSec) throws Exception { Connection con = null; PreparedStatement pstmt = null; java.sql.Timestamp currentTime = new java.sql.Timestamp(System.currentTimeMillis()); java.sql.Timestamp expTime = null; if (expInSec != 0) { expTime = new java.sql.Timestamp(System.currentTimeMillis() + expInSec * 1000); } try { con = getConnection(); pstmt = con.prepareStatement( "INSERT INTO DATA_CACHE (KEY, DATA, SIZE, CREATION_TIME_STAMP, EXPIRY_TIME_STAMP, LAST_ACCESS_TIME) values(?,?,?,?,?,?)"); int k = 1; pstmt.setString(k++, key); pstmt.setObject(k++, value); pstmt.setInt(k++, objectSize); pstmt.setTimestamp(k++, currentTime); pstmt.setTimestamp(k++, expTime); pstmt.setTimestamp(k++, currentTime); pstmt.executeUpdate(); } catch (Exception e) { if(e.getMessage().startsWith("Unique index or primary key violation:")) { try { pstmt = con.prepareStatement( "UPDATE DATA_CACHE SET DATA=?, SIZE=?, CREATION_TIME_STAMP=?, EXPIRY_TIME_STAMP=?, LAST_ACCESS_TIME=? WHERE KEY=?"); int k = 1; pstmt.setObject(k++, value); pstmt.setInt(k++, objectSize); pstmt.setTimestamp(k++, currentTime); pstmt.setTimestamp(k++, expTime); pstmt.setTimestamp(k++, currentTime); pstmt.setString(k++, key); pstmt.executeUpdate(); } catch (Exception er) { logger.log(Level.WARNING, "Update Error: " + er, er); throw er; } } else { logger.log(Level.WARNING, "Error: " + e, e); throw e; } } finally { try { pstmt.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } try { con.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } } } public void updateToCache(String key, Object value, int objectSize) throws Exception { Connection con = null; PreparedStatement pstmt = null; try { java.sql.Timestamp currentTime = new java.sql.Timestamp(System.currentTimeMillis()); con = getConnection(); pstmt = con.prepareStatement( "UPDATE DATA_CACHE SET DATA=?, SIZE=?, LAST_ACCESS_TIME=? WHERE KEY=?"); int k = 1; pstmt.setObject(k++, value); pstmt.setInt(k++, objectSize); pstmt.setTimestamp(k++, currentTime); pstmt.setString(k++, key); pstmt.executeUpdate(); } catch (Exception er) { logger.log(Level.WARNING, "Update Error: " + er, er); throw er; } finally { try { pstmt.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } try { con.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } } } public void updateToCache(String key, Object value, int objectSize, int expInSec) throws Exception { Connection con = null; PreparedStatement pstmt = null; try { java.sql.Timestamp currentTime = new java.sql.Timestamp(System.currentTimeMillis()); java.sql.Timestamp expTime = null; if (expInSec != 0) { expTime = new java.sql.Timestamp(System.currentTimeMillis() + expInSec * 1000); } con = getConnection(); pstmt = con.prepareStatement( "UPDATE DATA_CACHE SET DATA=?, SIZE=?, LAST_ACCESS_TIME=?, EXPIRY_TIME_STAMP=? WHERE KEY=?"); int k = 1; pstmt.setObject(k++, value); pstmt.setInt(k++, objectSize); pstmt.setTimestamp(k++, currentTime); pstmt.setTimestamp(k++, expTime); pstmt.setString(k++, key); pstmt.executeUpdate(); } catch (Exception er) { logger.log(Level.WARNING, "Update Error: " + er, er); throw er; } finally { try { pstmt.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } try { con.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } } } public Object getFromCache(String key) throws Exception { Object obj = null; Connection con = null; PreparedStatement pstmt = null; try { con = getConnection(); pstmt = con.prepareStatement("SELECT DATA,EXPIRY_TIME_STAMP FROM DATA_CACHE WHERE KEY = ?"); int k = 1; pstmt.setString(k++, key); ResultSet rs = pstmt.executeQuery(); java.sql.Timestamp expTime = null; if(rs.next()) { obj = rs.getObject("DATA"); expTime = rs.getTimestamp("EXPIRY_TIME_STAMP"); } else { if(QuickCached.DEBUG) logger.log(Level.FINE, "no value in db for key: {0}", key); } if (expTime != null && expTime.before(new Date())) { logger.log(Level.FINE, "Expired value for key {0}", key); obj = null; } } catch (Exception e) { logger.log(Level.WARNING, "Error: " + e, e); throw e; } finally { try { pstmt.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } try { con.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } } return obj; } public boolean deleteFromCache(String key) throws Exception { Connection con = null; int rowsAffected = 0; PreparedStatement pstmt = null; try { con = getConnection(); pstmt = con.prepareStatement("DELETE FROM DATA_CACHE WHERE KEY = ?"); int k = 1; pstmt.setString(k++, key); rowsAffected = pstmt.executeUpdate(); if(QuickCached.DEBUG) logger.log(Level.FINE, "rowsAffected: {0}", rowsAffected); } catch (Exception e) { logger.log(Level.WARNING, "Error: " + e, e); throw e; } finally { try { pstmt.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } try { con.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } } return rowsAffected > 0; } public void flushCache() throws Exception { Connection con = null; int rowsAffected = 0; PreparedStatement pstmt = null; if(QuickCached.DEBUG) logger.log(Level.FINE, "flush"); try { con = cp.getConnection(); pstmt = con.prepareStatement("DELETE FROM DATA_CACHE"); rowsAffected = pstmt.executeUpdate(); } catch (Exception e) { logger.log(Level.WARNING, "Error: " + e, e); throw e; } finally { try { pstmt.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } try { con.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } } logger.fine("rows cleared: " + rowsAffected); } public static void createTable() { Connection con = null; PreparedStatement pstmt = null; try { con = cp.getConnection(); /* try { pstmt = con.prepareStatement("DROP TABLE DATA_CACHE"); pstmt.execute(); } catch (Exception e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } * */ pstmt = con.prepareStatement("CREATE MEMORY TABLE DATA_CACHE(KEY nvarchar (250) PRIMARY KEY HASH," + "DATA OTHER NULL," + " SIZE numeric (18) NULL ," + " CREATION_TIME_STAMP datetime NULL ," + " EXPIRY_TIME_STAMP datetime NULL ," + " LAST_ACCESS_TIME datetime NULL);"); pstmt.execute(); pstmt = con.prepareStatement("CREATE UNIQUE HASH INDEX INDEX_DATA_CACHE_KEY ON DATA_CACHE (KEY); " + "CREATE INDEX INDEX_DATA_CACHE_EXP ON DATA_CACHE (EXPIRY_TIME_STAMP);" + "CREATE INDEX INDEX_DATA_CACHE_LST ON DATA_CACHE (LAST_ACCESS_TIME);"); pstmt.execute(); logger.fine("Table & indexes created"); PurgeOldData.startCleanUp(); } catch (Exception e) { logger.log(Level.WARNING, "Error: " + e, e); } finally { try { pstmt.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } try { con.close(); } catch (SQLException e1) { logger.log(Level.WARNING, "Error: " + e1, e1); } } } public boolean saveToDisk() { return false; } public boolean readFromDisk() { return false; } }