/* * Copyright (C) Lennart Martens * * Contact: lennart.martens AT UGent.be (' AT ' to be replaced with '@') */ /* * Created by IntelliJ IDEA. * User: Lennart * Date: 18-dec-02 * Time: 13:54:36 */ package com.compomics.util.db; import org.apache.log4j.Logger; import javax.swing.table.AbstractTableModel; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.ResultSetMetaData; import java.util.Vector; import java.io.Writer; import java.io.IOException; /* * CVS information: * * $Revision: 1.5 $ * $Date: 2007/10/16 10:07:37 $ */ /** * This class wraps a DB resultset in an 'offline' object. * * @author Lennart Martens */ public class DBResultSet extends AbstractTableModel { // Class specific log4j logger for DBResultSet instances. Logger logger = Logger.getLogger(DBResultSet.class); /** * The number of columns in this resultset. */ private int iColCount = 0; /** * The number of rows in this resultset. */ private int iRowCount = 0; /** * The column names in this resultset. */ private String[] iColNames = null; /** * The data. */ private Object[][] iData = null; /** * Default constructor, just creates an empty resultset. */ public DBResultSet() { iColNames = new String[]{}; iData = new Object[][]{{}}; } /** * This constructor takes a ResultSet from which the data * is read. This ResultSet will not be closed by this constructor, * so it remains available and the closing is up to the caller! * Nullreplace is FALSE for this constructor! * * @param aRS ResultSet from which to read the data. Closing the ResultSet * is up to the caller!! * @exception SQLException whenever reading the resultset failed. */ public DBResultSet(ResultSet aRS) throws SQLException { this(aRS, false); } /** * This constructor takes a ResultSet from which the data * is read. This ResultSet will not be closed by this constructor, * so it remains available and the closing is up to the caller! * Notice that the null replace flag allows you to replace 'null' values * returned by the DB to the String "(null)". * * @param aRS ResultSet from which to read the data. Closing the ResultSet * is up to the caller!! * @param aNullReplace boolean to indicate whether 'null' values returned by * the DB should be converted into "(null)" Strings ('true') * or not ('false'). * @exception SQLException whenever reading the resultset failed. */ public DBResultSet(ResultSet aRS, boolean aNullReplace) throws SQLException { ResultSetMetaData rsmd = aRS.getMetaData(); // ColCount. iColCount = rsmd.getColumnCount(); iColNames = new String[iColCount]; // Col names. for(int i=0;i<iColCount;i++) { iColNames[i] = rsmd.getColumnLabel(i+1); } // Cycle rows. Vector rows = new Vector(); while(aRS.next()) { Object[] temp = new Object[iColCount]; for(int i = 0; i < temp.length; i++) { temp[i] = aRS.getObject(i+1); if(aNullReplace) { // Change 'null' values with the String (null). if(temp[i] == null) { temp[i] = "(null)"; } } } rows.add(temp); } // Transform Vector. iRowCount = rows.size(); iData = new Object[iRowCount][iColCount]; for(int i = 0; i < iData.length; i++) { iData[i] = (Object[])rows.get(i); } } /** * This method reports on all the columnn ames. * * @return String[] with all the column names. */ public String[] getColumnNames() { return this.iColNames; } /** * This method reports on the data stored in the resultset. * * @return Object[][] with the data. */ public Object[][] getData() { return this.iData; } /** * This method reports on the number of columns in the resultset. * * @return int with the columncount. */ public int getColumnCount() { return this.iColCount; } /** * This method reports on the number of rows in the resultset. * * @return int with the rowcount. */ public int getRowCount() { return this.iRowCount; } /** * Returns the value for the cell at <code>columnIndex</code> and * <code>rowIndex</code>. * * @param rowIndex the row whose value is to be queried * @param columnIndex the column whose value is to be queried * @return the value Object at the specified cell */ public Object getValueAt(int rowIndex, int columnIndex) { return iData[rowIndex][columnIndex]; } /** * Returns <code>Object.class</code> regardless of <code>columnIndex</code>. * * @param columnIndex the column being queried * @return the Object.class */ public Class getColumnClass(int columnIndex) { // If a data column conrtains only 'null', we should // give a Class for it anyway, since it requires a renderer! // String seems to be the natural choice. Class result = String.class; // Cycle the whole column to see if there is a non-null value. // If there is any, take it and break the loop. If there is none, // we still have the default String class. for (int i = 0; i < iData.length; i++) { if(iData[i][columnIndex] != null) { result = iData[i][columnIndex].getClass(); break; } } return result; } /** * Returns a default name for the column using spreadsheet conventions: * A, B, C, ... Z, AA, AB, etc. If <code>column</code> cannot be found, * returns an empty string. * * @param column the column being queried * @return a string containing the default name of <code>column</code> */ public String getColumnName(int column) { return iColNames[column]; } /** * This method allows the caller to write the current dataset to the * specified Writer. Note that flushing and closing the writer is up to the * caller. * * @param out Writer to print to. Note that flushing and closing this * writer is up to the caller. * @param aSeparator String with the separator character(s) to use. * @exception IOException when something goes wrong. */ public void writeToCSVFile(Writer out, String aSeparator) throws IOException { // Write headers first. for(int i=0;i<iColCount;i++) { out.write(aSeparator + this.getColumnName(i)); } out.write("\n"); for(int i=0;i<iRowCount;i++) { for(int j=0;j<iColCount;j++) { String text = "" + this.getValueAt(i,j); if(text.indexOf("<html>") >= 0) { // Replace 'html' tags with 'body' tags for Excel compatibility. // Remove 'html' tags. int start = -1; while((start = text.indexOf("<html>")) >= 0) { text = text.substring(0, start) + text.substring(start + 6); } while((start = text.indexOf("</html>")) >= 0) { text = text.substring(0, start) + text.substring(start + 7); } } out.write(aSeparator + text); } out.write("\n"); } } /** * This method allows the caller to write the current dataset to the * specified Writer. Note that flushing and closing the writer is up to the * caller. * * @param out Writer to print to. Note that flushing and closing this * writer is up to the caller. * @param aBorderstyle int with the HTML table border tag style for the table. * @exception IOException when something goes wrong. */ public void writeToHTMLTable(Writer out, int aBorderstyle) throws IOException { // Write headers first. out.write("<table border=\"" + aBorderstyle + "\">\n"); out.write(" <caption align=\"bottom\">This table was generated by the DBResultSet Java Object.</caption>\n"); out.write(" <tr>\n"); for(int i=0;i<iColCount;i++) { out.write(" <th>" + this.getColumnName(i) + "</th>\n"); } out.write(" </tr>\n"); for(int i=0;i<iRowCount;i++) { out.write(" <tr>\n"); for(int j=0;j<iColCount;j++) { Object o = this.getValueAt(i,j); String text = null; if(o == null) { text = " "; } else { text = o.toString(); if(text.trim().equals("")) { text = " "; } else if(text.indexOf("<html>") >= 0) { // Remove 'html' tags. int start = -1; while((start = text.indexOf("<html>")) >= 0) { text = text.substring(0, start) + text.substring(start + 6); } while((start = text.indexOf("</html>")) >= 0) { text = text.substring(0, start) + text.substring(start + 7); } } } out.write(" <td>" + text + "</td>\n"); } out.write(" </tr>\n"); } out.write("</table>\n"); } }