/* * Copyright (c) 2011, the Last.fm Java Project and Committers * All rights reserved. * * Redistribution and use of this software in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package de.umass.lastfm.cache; import java.io.*; import java.sql.*; /** * Generic class for caching into a database. Its constructor takes a {@link Connection} instance, which must be opened and closed by the * client. SQL code used in this class should work with all common databases (which support varchar, timestamp and longvarchar * datatypes).<br/> For more specialized versions of this class for different databases one may extend this class and override methods as * needed. * * @author Janni Kovacs */ public class DatabaseCache extends Cache { protected static final String DEFAULT_TABLE_NAME = "LASTFM_CACHE"; protected String tableName = DEFAULT_TABLE_NAME; protected Connection conn; public DatabaseCache(Connection connection) throws SQLException { this.conn = connection; ResultSet tables = conn.getMetaData().getTables(null, null, tableName, null); if (!tables.next()) { createTable(); } } protected void createTable() throws SQLException { PreparedStatement stmt = conn.prepareStatement("CREATE TABLE " + tableName + " (key varchar, expiration_date timestamp, response longvarchar);"); stmt.execute(); stmt.close(); } public boolean contains(String cacheEntryName) { try { PreparedStatement stmt = conn.prepareStatement("SELECT key FROM " + tableName + " WHERE key = ?;"); stmt.setString(1, cacheEntryName); ResultSet result = stmt.executeQuery(); boolean b = result.next(); stmt.close(); return b; } catch (SQLException e) { return false; } } public InputStream load(String cacheEntryName) { try { PreparedStatement stmt = conn.prepareStatement("SELECT response FROM " + tableName + " WHERE key = ?;"); stmt.setString(1, cacheEntryName); ResultSet result = stmt.executeQuery(); if (result.next()) { String s = result.getString("response"); stmt.close(); return new ByteArrayInputStream(s.getBytes("UTF-8")); } stmt.close(); } catch (SQLException e) { // ignore } catch (UnsupportedEncodingException e) { // won't happen } return null; } public void remove(String cacheEntryName) { try { PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + tableName + " WHERE key = ?;"); stmt.setString(1, cacheEntryName); stmt.execute(); stmt.close(); } catch (SQLException e) { // ignore } } public void store(String cacheEntryName, InputStream inputStream, long expirationDate) { try { InputStreamReader reader = new InputStreamReader(inputStream); StringBuilder sb = new StringBuilder(inputStream.available()); char[] buf = new char[2048]; int read; while ((read = reader.read(buf, 0, buf.length)) != -1) { sb.append(buf, 0, read); } PreparedStatement stmt = conn.prepareStatement("INSERT INTO " + tableName + " (key, expiration_date, response) VALUES(?, ?, ?);"); stmt.setString(1, cacheEntryName); stmt.setTimestamp(2, new Timestamp(expirationDate)); stmt.setString(3, sb.toString()); stmt.execute(); stmt.close(); } catch (SQLException e) { e.printStackTrace(); // ignore } catch (UnsupportedEncodingException e) { e.printStackTrace(); // won't happen } catch (IOException e) { e.printStackTrace(); // better won't happen } } public boolean isExpired(String cacheEntryName) { try { PreparedStatement stmt = conn.prepareStatement("SELECT expiration_date FROM " + tableName + " WHERE key = ?;"); stmt.setString(1, cacheEntryName); ResultSet result = stmt.executeQuery(); if (result.next()) { Timestamp timestamp = result.getTimestamp("expiration_date"); long expirationDate = timestamp.getTime(); stmt.close(); return expirationDate < System.currentTimeMillis(); } } catch (SQLException e) { // ignore } return false; } public void clear() { try { PreparedStatement stmt = conn.prepareStatement("DELETE FROM " + tableName + ";"); stmt.execute(); stmt.close(); } catch (SQLException e) { // ignore } } }