package tml.sql; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; import java.util.Hashtable; import java.util.Properties; import org.apache.log4j.Logger; import org.apache.lucene.document.Document; import tml.Configuration; import tml.storage.Repository; /** * This class represents the metadata database. When annotations are obtained * for a document, those annotations are stored in the metadata database. * * Annotations can be anything provided by an Annotator class, for example * the PennTree annotator parses a sentence and stores the penn string associated * with the parse. * * @author Jorge Villalon * */ public class DbConnection { private static Logger logger = Logger.getLogger(DbConnection.class); private static Connection connection = null; private static String url; private Connection getConnection() { if(connection != null) return connection; try { Properties props = Configuration.getTmlProperties(); connection = DriverManager.getConnection( url, props.getProperty("tml.database.username"), props.getProperty("tml.database.password")); return connection; } catch (Exception e) { e.printStackTrace(); logger.error("Couldn't connect to DB server. Check parameters!"); return null; } } public void cleanMetaDataStorage() { logger.info("Cleaning meta data storage, all documents will be lost!"); try { Connection conn = getConnection(); String sql = "delete from tml_documents"; PreparedStatement statement = conn.prepareStatement(sql); statement.executeUpdate(); sql = "delete from tml_documents_annotations"; statement = getConnection().prepareStatement(sql); statement.executeUpdate(); sql = "delete from tml_documents_reviews"; statement = getConnection().prepareStatement(sql); statement.executeUpdate(); } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); } } public DbConnection() throws SQLException, IOException { Properties props = Configuration.getTmlProperties(); url = props.getProperty("tml.database.url.protocol") + props.getProperty("tml.database.url.db"); String driver = Configuration.getTmlProperties().getProperty("tml.database.driver"); try { Class.forName(driver).newInstance(); } catch (Exception e) { logger.error("Problem with database driver installation"); e.printStackTrace(); throw new IOException(e); } try { DriverManager.getConnection( url, props.getProperty("tml.database.username"), props.getProperty("tml.database.password")); } catch (SQLException e) { logger.error("Problems accessing the annotations database. " + "Please check for the database and the user defined in the tml.properties file. " + "Read the README.txt file for installation instructions."); logger.error("User: " + props.getProperty("tml.database.username") + " URL:" + url); logger.error(e.getLocalizedMessage()); throw e; } logger.info("Metadata:\t\tStoring metadata info in DB " + driver + " at " + url); } public String[][] getDocuments() throws Exception { PreparedStatement statement = getConnection().prepareStatement("select document_externalid, document_annotated from tml_documents where document_type = 'document'"); String[] cols = new String[] {"document_externalid","document_annotated"}; return executeQuery(statement, cols); } public String[][] getSubDocuments(String externalId) throws Exception { PreparedStatement statement = getConnection().prepareStatement("select document_externalid, document_annotated from tml_documents where document_externalid like ?"); statement.setString(1, "%" + externalId); String[] cols = new String[] {"document_externalid","document_annotated"}; return executeQuery(statement, cols); } public void insertDocument(Repository repo, Document document) throws SQLException { Connection conn = getConnection(); Date now = new Date(); String sql = "delete from tml_documents where document_externalid = ?"; PreparedStatement statement = conn.prepareStatement(sql); statement.setString(1, document.get(repo.getLuceneExternalIdField())); statement.executeUpdate(); sql = "insert into tml_documents " + " (document_title, document_url, document_externalid, document_content, document_type, document_date, document_annotated) values (?,?,?,?,?,?,0)"; statement = getConnection().prepareStatement(sql); statement.setString(1, document.get(repo.getLuceneTitleField())); statement.setString(2, document.get(repo.getLuceneUrlField())); statement.setString(3, document.get(repo.getLuceneExternalIdField())); statement.setString(4, document.get(repo.getLuceneContentField())); statement.setString(5, document.get(repo.getLuceneTypeField())); statement.setDate(6, new java.sql.Date(now.getTime())); statement.executeUpdate(); } public void setAnnotation(String documentId, String field, String annotation) { try { Connection conn = getConnection(); Date now = new Date(); String sql = "delete from tml_documents_annotations where document_externalid = ? and annotation_field = ?"; PreparedStatement statement = conn.prepareStatement(sql); statement.setString(1, documentId); statement.setString(2, field); statement.execute(); sql = "insert into tml_documents_annotations (document_externalid, annotation_field, annotation_value, annotation_date) " + " values (?,?,?,?)"; statement = getConnection().prepareStatement(sql); statement.setString(1, documentId); statement.setString(2, field); statement.setString(3, annotation); statement.setDate(4, new java.sql.Date(now.getTime())); statement.execute(); sql = "update tml_documents set document_annotated = 1 " + "where document_externalid = ?"; statement = getConnection().prepareStatement(sql); statement.setString(1, documentId); statement.execute(); } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); } } public boolean isDirty(Date date) { Date maxAnnotation = new Date(0); Date maxDocument = new Date(0); try { Connection conn = getConnection(); String sql = "select max(annotation_date) as date from tml_documents_annotations"; PreparedStatement statement = conn.prepareStatement(sql); String[] columns = new String[]{"date"}; String[][] m = executeQuery(statement,columns); if(m[0][0] != null) maxAnnotation = new Date(Long.parseLong(m[0][0])); sql = "select max(document_date) as date from tml_documents"; statement = conn.prepareStatement(sql); m = executeQuery(statement,columns); if(m[0][0] != null) maxDocument = new Date(Long.parseLong(m[0][0])); logger.info(date); logger.info(maxAnnotation); logger.info(maxDocument); } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); } if(date.before(maxDocument) || date.before(maxAnnotation)) return true; else return false; } public String getAnnotation(String documentId, String field) { String sql = "select annotation_value from tml_documents_annotations " + "where document_externalid = ? and annotation_field = ?"; String[] columns = new String[]{"annotation_value"}; try { Connection conn = getConnection(); PreparedStatement statement = conn.prepareStatement(sql); statement.setString(1, documentId); statement.setString(2, field); String[][] result = executeQuery(statement, columns); if(result.length == 0) { return null; } return result[0][0]; } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); } return null; } public String getReview(String documentId, String reviewName, String user) { String sql = "select review_value from tml_documents_reviews " + "where document_externalid = ? and review_name = ? and review_author = ?"; String[] columns = new String[]{"review_value"}; try { Connection conn = getConnection(); PreparedStatement statement = conn.prepareStatement(sql); statement.setString(1, documentId); statement.setString(2, reviewName); statement.setString(3, user); String[][] result = executeQuery(statement, columns); if(result.length == 0) { return null; } return result[0][0]; } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); } return null; } public void setReview(String documentId, String review_name, String review, String user) { try { Connection conn = getConnection(); Date now = new Date(); String sql = "delete from tml_documents_reviews where document_externalid = ? and review_name = ? and review_author = ?"; PreparedStatement statement = conn.prepareStatement(sql); statement.setString(1, documentId); statement.setString(2, review_name); statement.setString(3, user); statement.execute(); sql = "insert into tml_documents_reviews (document_externalid, review_name, review_author, review_value, review_date) " + " values (?,?,?,?,?)"; statement = getConnection().prepareStatement(sql); statement.setString(1, documentId); statement.setString(2, review_name); statement.setString(3, user); statement.setString(4, review); statement.setDate(5, new java.sql.Date(now.getTime())); statement.execute(); } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); } } public String[][] getUnannotatedDocument() { try { Connection conn = getConnection(); conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); String sql = "update tml_documents " + "set document_annotated = 2 where document_annotated = 0"; PreparedStatement statement = conn.prepareStatement(sql); int rowcount = statement.executeUpdate(); if(rowcount == 0) { return null; } sql = "select document_externalid, document_type from tml_documents " + "where document_annotated = 2"; String[] columns = new String[]{"document_externalid","document_type"}; statement = conn.prepareStatement(sql); String[][] result = executeQuery(statement, columns); if(result.length == 0) { return null; } return result; } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); } return null; } public String[][] executeQuery(PreparedStatement st, String[] columns) throws Exception { Hashtable<String, ArrayList<String>> results = new Hashtable<String, ArrayList<String>>(); if(columns == null) throw new Exception("Columns is null"); try { ResultSet resultSet = st.executeQuery(); for(String column : columns) { results.put(column, new ArrayList<String>()); } while(resultSet.next()) { for(String column : columns) { if(resultSet.getObject(column)!=null) results.get(column).add(resultSet.getObject(column).toString()); else results.get(column).add(null); } } } catch (Exception e) { e.printStackTrace(); throw new Exception(e.getMessage()); } return getTableFromHash(results, columns); } private String[][] getTableFromHash(Hashtable<String, ArrayList<String>> h, String[] sortedKeys) throws Exception { if(h.keySet().size()==0) return null; @SuppressWarnings("unchecked") int rows = ((ArrayList<String>)h.values().toArray()[0]).size(); String[][] output = new String[rows][h.keySet().size()]; for(int i=0;i<rows;i++) { int j=0; for(String key : sortedKeys) { output[i][j] = h.get(key).get(i); j++; } } return output; } public void close() { if(connection != null) try { connection.close(); } catch (SQLException e) { logger.error("Couldn't close DB connection"); connection = null; } } }