package org.lysty.db; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import javax.swing.ProgressMonitor; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.log4j.Logger; import org.h2.tools.RunScript; import org.lysty.dao.Song; import org.lysty.extractors.FeatureExtractor; import org.lysty.ui.Modification; import org.lysty.util.Utils; public class DBHandler { private static final long INSERTION_FAIL_ID = -1; public static final String DB_FOLDER_PROP = "db_dir"; private static final String SQLS_DIR = "sqls"; public static DBHandler self = null; public static SqlSessionFactory sqlSessionFactory; private static Logger logger = Logger.getLogger(DBHandler.class); private DBHandler() throws IOException { File file = new File("config/mybatis-config.xml"); InputStream inputStream = null; inputStream = new FileInputStream(file); Properties props = new Properties(); props.put(DB_FOLDER_PROP, Utils.getAppDirectoryFolder(Utils.DB_FOLDER) .getAbsolutePath()); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, props); try { updateDB(); } catch (SQLException e) { logger.error("Could not update DB", e); } } public static void updateDB() throws FileNotFoundException, SQLException { int n = getLastDBUpdateScript(); File sqlsDir = new File(SQLS_DIR); File[] scripts = sqlsDir.listFiles(new FileFilter() { @Override public boolean accept(File file) { if (file.getName().endsWith(".sql")) return true; return false; } }); File[] scriptsOrdered = new File[scripts.length]; for (File script : scripts) { scriptsOrdered[getScriptNumber(script)] = script; } SqlSession session = DBHandler.sqlSessionFactory.openSession(); try { Connection connection = session.getConnection(); for (int i = n + 1; i < scriptsOrdered.length; i++) { logger.info("Running db script: " + scriptsOrdered[i].getName()); RunScript .execute(connection, new FileReader(scriptsOrdered[i])); setLastRunScriptNum(i); } logger.info("DB Update complete"); } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } } private static void setLastRunScriptNum(int last) { SqlSession session = DBHandler.sqlSessionFactory.openSession(); try { DBMapper mapper = session.getMapper(DBMapper.class); mapper.setLastDBScriptNum(last); session.commit(); } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } } private static int getScriptNumber(File script) { String numStr = script.getName().split("_")[0]; return Integer.parseInt(numStr); } private static int getLastDBUpdateScript() { SqlSession session = DBHandler.sqlSessionFactory.openSession(); Integer last = null; try { DBMapper mapper = session.getMapper(DBMapper.class); last = mapper.getLastDBScriptNum(); if (last == null) { return -1; } return last; } catch (Exception e) { logger.error("DB Error", e); return -1; } finally { session.close(); } } public static DBHandler getInstance() { if (self == null) { try { self = new DBHandler(); } catch (IOException e) { logger.error("Error creating DBHandler", e); } } return self; } // DB Calls public long insertSong(Song song) { if (song.getFile().isDirectory()) return -1; SqlSession session = DBHandler.sqlSessionFactory.openSession(); Long id = INSERTION_FAIL_ID; try { DBMapper mapper = session.getMapper(DBMapper.class); id = mapper.getSongId(song); if (id == null || id == 0) { id = mapper.insertSong(song); session.commit(); id = mapper.getSongId(song); } } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } return id; } public void insertAttributes(Song song) { SqlSession session = DBHandler.sqlSessionFactory.openSession(); try { DBMapper mapper = session.getMapper(DBMapper.class); Iterator<Entry<String, String>> iter = song.getAttributes() .entrySet().iterator(); Entry<String, String> entry; while (iter.hasNext()) { entry = iter.next(); mapper.insertAttribute(song.getId(), entry.getKey(), entry.getValue()); } session.commit(); } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } } /** * Fills the attributes from the db * * @param song */ public void fillAttributes(Song song) { SqlSession session = DBHandler.sqlSessionFactory.openSession(); try { DBMapper mapper = session.getMapper(DBMapper.class); Map<String, String> attribs = getAttribMapFromMapList(mapper .getAttributes(song)); song.setAttributes(attribs); } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } } private Map<String, String> getAttribMapFromMapList( List<Map<String, String>> listOfMap) { Map<String, String> map = new HashMap<String, String>(); for (int i = 0; i < listOfMap.size(); i++) { String key = listOfMap.get(i).get("ATTRIBUTE"); String value = listOfMap.get(i).get("VALUE"); map.put(key, value); } return map; } public Song getSong(File file) { Song song = new Song(); song.setFile(file); SqlSession session = DBHandler.sqlSessionFactory.openSession(); Long id = null; try { DBMapper mapper = session.getMapper(DBMapper.class); id = mapper.getSongId(song); if (id == null) { return null; } song.setId(id); fillAttributes(song); } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } return song; } public List<Song> getSongs(File folder) { Song song; long id = 0; SqlSession session = DBHandler.sqlSessionFactory.openSession(); try { String path = folder == null ? "%" : folder.getPath() + "%"; DBMapper mapper = session.getMapper(DBMapper.class); List<Map<String, String>> mapList = mapper.getSongs(path); Map<Long, Song> songMap = new HashMap<Long, Song>(); for (Map<String, String> mapEntry : mapList) { try { id = Long.parseLong(String.valueOf(mapEntry.get("ID"))); } catch (Exception e) { logger.error("DB Error", e); } song = songMap.get(id); if (song == null) { song = new Song(); song.setId(id); song.setName(mapEntry.get("NAME")); song.setFile(new File(mapEntry.get("PATH"))); songMap.put(id, song); } song.addAttribute(mapEntry.get("ATTRIBUTE"), mapEntry.get("VALUE")); } return new ArrayList<Song>(songMap.values()); } catch (Exception e) { logger.error("DB Error", e); return null; } finally { session.close(); } } public void setFolderIndexTimestamp(File folder, Long time) { SqlSession session = DBHandler.sqlSessionFactory.openSession(); try { DBMapper mapper = session.getMapper(DBMapper.class); mapper.setFolderIndexTimestamp(folder.getPath(), time); session.commit(); } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } } private Map<String, Long> getIndexMapFromList( List<Map<String, String>> listOfMap, String keyAttrib, String valueAttrib) { Map<String, Long> map = new HashMap<String, Long>(); for (int i = 0; i < listOfMap.size(); i++) { String key = listOfMap.get(i).get(keyAttrib); Long value = Long.parseLong(String.valueOf( listOfMap.get(i).get(valueAttrib)).toString()); map.put(key, value); } return map; } public Map<String, Long> getFolderIndexMap() { SqlSession session = DBHandler.sqlSessionFactory.openSession(); try { DBMapper mapper = session.getMapper(DBMapper.class); Map<String, Long> map = getIndexMapFromList( mapper.getFolderIndexMap(), "FOLDER", "LASTINDEXTIME"); if (map == null) return new HashMap<String, Long>(); return map; } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } return null; } public Map<String, Long> getExtractorTimestampMap() { SqlSession session = DBHandler.sqlSessionFactory.openSession(); try { DBMapper mapper = session.getMapper(DBMapper.class); Map<String, Long> map = getIndexMapFromList( mapper.getExtractorTimestampMap(), "NAME", "ADDEDTIME"); if (map == null) return new HashMap<String, Long>(); return map; } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } return null; } /** * Returns the timestamp the extractor was added to the system. If no record * is found, a new record is added and current time is returned; * * @param extractor * @param currentTimeMillis * @return */ public Long getSetExtractorTimestamp(FeatureExtractor extractor) { SqlSession session = DBHandler.sqlSessionFactory.openSession(); Long timestamp = null; try { DBMapper mapper = session.getMapper(DBMapper.class); timestamp = mapper.getExtractorTimestamp(extractor.getClass() .getName()); if (timestamp == null) { timestamp = System.currentTimeMillis(); mapper.insertExtractorTimestamp(extractor.getClass().getName(), timestamp); session.commit(); } return timestamp; } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } return null; } public void applyModifications(List<Modification> changes, ProgressMonitor listener) { SqlSession session = DBHandler.sqlSessionFactory.openSession(); Long timestamp = null; try { DBMapper mapper = session.getMapper(DBMapper.class); int currentProgress = 0; for (Modification change : changes) { currentProgress++; if (listener != null) listener.setProgress(currentProgress); try { if (change.getFeature() == null) { // song addition if (!change.getSong().getFile().isDirectory()) { // only // add // actual // files insertSong(change.getSong()); logger.info("Inserted song: " + change.getSong().getFile()); } } else { DBHandler.getInstance().setAttribute(change.getSong(), change.getFeature(), change.getNewValue()); } } catch (Exception e) { logger.error( "Error applying change: set " + change.getSong() + " " + change.getFeature() + " to " + change.getNewValue(), e); } } } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } } private void setAttribute(Song song, String feature, String newValue) { if (song.getFile().isDirectory()) return; if (song.getId() == 0) { // the song was not in the db at the time of setting the attribute // it is assumed that the song is inserted before setting the // attribute Song songInDb = getSong(song.getFile()); if (songInDb == null) { // ideally should not reach. coded for safety insertSong(song); songInDb = getSong(song.getFile()); } song = songInDb; } SqlSession session = DBHandler.sqlSessionFactory.openSession(); Long timestamp = null; try { DBMapper mapper = session.getMapper(DBMapper.class); mapper.setAttribute(song.getId(), feature, newValue); logger.info("set " + feature + " of " + song.getFile().getName() + " to " + newValue); } catch (Exception e) { logger.error("DB Error", e); } finally { session.close(); } } public List<Song> getAllSongs() { return getSongs(null); } }