package library;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.List;
import songstreams.SongStream;
import songstreams.YouTubeSongStream;
import library.conditions.TrueCondition;
import library.conditions.URLCondition;
import library.exceptions.InvalidQueryException;
import library.interfaces.Condition;
public class Library {
/**
* Holds the connection to the database
*/
private Connection connection;
/**
* Table column names
*/
public static final String ARTIST = "Artist";
public static final String ALBUM = "Album";
public static final String TITLE = "Title";
public static final String GENRE = "Genre";
public static final String YEAR = "Year";
public static final String TRACK_NUM = "TrackNum";
public static final String BPM = "BPM";
public static final String URL = "URL";
public static final String FILES = "files";
public static final String STREAMS = "streams";
/**
* Instantiates a Library with the specified database path
* @param path - the path to the database
* @throws Exception if an error occurs opening/creating the database
*/
public Library(File path) throws Exception {
Class.forName("org.h2.Driver");
connection = DriverManager.getConnection("jdbc:h2:" + path.getAbsolutePath(),"sa","");
createTable(FILES);
createTable(STREAMS);
}
private void createTable(String tableName) throws SQLException {
Statement statement = connection.createStatement();
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + "(" +
ARTIST + " VARCHAR (100)," +
TITLE + " VARCHAR (100)," +
ALBUM + " VARCHAR (100)," +
GENRE + " VARCHAR (30)," +
YEAR + " INTEGER," +
TRACK_NUM + " INTEGER," +
BPM + " FLOAT," +
URL + " VARCHAR(1000) NOT NULL UNIQUE)");
}
/**
* Adds a new song to this Library and its database
* @param song - the song to be added
* @return <b>true</b> if the song was added, <b>false</b> otherwise
* @throws SQLException if an error occurs storing the song in the database
* @throws IOException if an error occurs writing the Song to a blob
*/
public boolean addSong(SongStream song) throws SQLException, IOException {
if(song instanceof YouTubeSongStream)
return addSongToTable(song, URL);
if(song instanceof SongStream)
return addSongToTable(song, URL);
return false;
}
private boolean addSongToTable(SongStream song, String table) throws SQLException {
PreparedStatement statement = connection.prepareStatement("INSERT INTO " + table + "(" +
ARTIST + "," +
TITLE + "," +
ALBUM + "," +
GENRE + "," +
YEAR + "," +
TRACK_NUM + "," +
BPM + "," +
URL + ") VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
statement.setString(1, song.getArtist());
statement.setString(2, song.getTitle());
statement.setString(3, song.getAlbum());
statement.setString(4, song.getGenre());
statement.setInt(5, song.getYear());
statement.setInt(6, song.getTrackNum());
statement.setFloat(7, song.getBpm());
statement.setString(8, song.getURL().toString());
statement.executeUpdate();
connection.commit();
statement.close();
return true;
}
/**
* Returns a List with all Songs in this Library
* @param sortBy - the column to sort by
* @return a List with all Songs in this Library
* @throws Exception Exception if an error occurs fetching the songs from the database or reading the Songs from the blobs
*/
public List<SongStream> getAllSongs(String sortBy) throws Exception {
return getSongsByCondition(new TrueCondition(), sortBy);
}
private List<SongStream> getSongsByConditionFromTable(Condition cond, String table, String sortBy) throws SQLException, Exception {
String condition = cond.getSQLCondition();
PreparedStatement statement = connection.prepareStatement("SELECT * FROM " + table + " WHERE " + condition + " ORDER BY " + sortBy);
cond.prepareSQLStatement(statement, 1);
ResultSet result = statement.executeQuery();
List<SongStream> songs = new LinkedList<SongStream>();
while(result.next()) {
songs.add(new SongStream(
result.getString(ARTIST),
result.getString(TITLE),
result.getString(ALBUM),
result.getString(GENRE),
result.getInt(YEAR),
result.getInt(TRACK_NUM),
result.getInt(BPM),
result.getString(URL)));
}
return songs;
}
/**
* Get all songs from this library that match the given condition
* @param cond - the condition which the songs have to match
* @param sortBy - the table column to sort the results by
* @return a List of all songs matching the given condition in this library
* @throws Exception
*/
public List<SongStream> getSongsByCondition(Condition cond, String sortBy) throws Exception {
List<SongStream> songs = new LinkedList<SongStream>();
songs.addAll(getSongsByConditionFromTable(cond, FILES, sortBy));
songs.addAll(getSongsByConditionFromTable(cond, STREAMS, sortBy));
return songs;
}
public List<SongStream> getAllSongs() throws Exception {
return getAllSongs(ARTIST);
}
/**
* Get all songs from this library that match the given condition
* @param cond - the condition which the songs have to match
* @return a List of all songs matching the given condition in this library
* @throws Exception
*/
public List<SongStream> getSongsByCondition(Condition cond) throws Exception {
return getSongsByCondition(cond, ARTIST);
}
/**
* Checks if the Library contains a Song with the given url
* @param url - the url to be matched.
* @return <b>true</b> if this Library contains a song with the given URL, <b>false</b> otherwise.
*/
public boolean contains(URL url) {
try {
Condition cond = new URLCondition(url.toString());
List<SongStream> songs = getSongsByCondition(cond);
return songs.size() > 0;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* Gets the Song with the given URL
* @param string - the URL of the song
* @return a SongStream for the URL or null if no such song exists
* @throws Exception
* @throws InvalidQueryException
*/
public SongStream getSong(String string) throws InvalidQueryException, Exception {
List<SongStream> result = getSongsByCondition(new URLCondition(string));
if(result.size() == 0)
return null;
return result.get(0);
}
}