Frames | No Frames |
1: /** 2: * ======================================== 3: * JFreeReport : a free Java report library 4: * ======================================== 5: * 6: * Project Info: http://reporting.pentaho.org/ 7: * 8: * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors. 9: * 10: * This library is free software; you can redistribute it and/or modify it under the terms 11: * of the GNU Lesser General Public License as published by the Free Software Foundation; 12: * either version 2.1 of the License, or (at your option) any later version. 13: * 14: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 15: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16: * See the GNU Lesser General Public License for more details. 17: * 18: * You should have received a copy of the GNU Lesser General Public License along with this 19: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, 20: * Boston, MA 02111-1307, USA. 21: * 22: * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 23: * in the United States and other countries.] 24: * 25: * ------------ 26: * $Id: ScrollableResultSetTableModel.java 2725 2007-04-01 18:49:29Z taqua $ 27: * ------------ 28: * (C) Copyright 2000-2005, by Object Refinery Limited. 29: * (C) Copyright 2005-2007, by Pentaho Corporation. 30: */ 31: package org.jfree.report.modules.misc.tablemodel; 32: 33: import java.sql.ResultSet; 34: import java.sql.ResultSetMetaData; 35: import java.sql.SQLException; 36: import javax.swing.table.AbstractTableModel; 37: 38: import org.jfree.util.Log; 39: 40: /** 41: * A tableModel which is backed up by a java.sql.ResultSet. Use this to directly feed your 42: * database data into JFreeReport. If you have trouble using this TableModel and you have 43: * either enough memory or your query result is not huge, you may want to use 44: * <code>ResultSetTableModelFactory.generateDefaultTableModel (ResultSet rs)</code>. That 45: * implementation will read all data from the given ResultSet and keep that data in 46: * memory. 47: * <p/> 48: * Use the close() function to close the ResultSet contained in this model. 49: * 50: * @author Thomas Morgner 51: */ 52: public class ScrollableResultSetTableModel extends AbstractTableModel 53: implements CloseableTableModel 54: { 55: /** 56: * The scrollable ResultSet source. 57: */ 58: private ResultSet resultset; 59: /** 60: * The ResultSetMetaData object for this result set. 61: */ 62: private ResultSetMetaData dbmd; 63: /** 64: * The number of rows in the result set. 65: */ 66: private int rowCount; 67: /** 68: * Defines the column naming mode. 69: */ 70: private final boolean labelMapMode; 71: /** 72: * The column types as read from the result set. 73: */ 74: private Class[] types; 75: 76: /** 77: * Constructs the model. 78: * 79: * @param resultset the result set. 80: * @param labelMapMode defines, whether to use column names or column labels to compute 81: * the column index. 82: * @throws SQLException if there is a problem with the result set. 83: */ 84: public ScrollableResultSetTableModel (final ResultSet resultset, 85: final boolean labelMapMode) 86: throws SQLException 87: { 88: this.labelMapMode = labelMapMode; 89: if (resultset != null) 90: { 91: updateResultSet(resultset); 92: } 93: else 94: { 95: close(); 96: } 97: } 98: 99: /** 100: * Creates a new scrollable result set with no resultset assigned and the specified 101: * label map mode. 102: * 103: * @param labelMapMode defines, whether to use column names or column labels to compute 104: * the column index. 105: */ 106: protected ScrollableResultSetTableModel (final boolean labelMapMode) 107: { 108: this.labelMapMode = labelMapMode; 109: } 110: 111: /** 112: * Returns the column name mode used to map column names into column indices. If true, 113: * then the Label is used, else the Name is used. 114: * 115: * @return true, if the column label is used for the mapping, false otherwise. 116: * 117: * @see ResultSetMetaData#getColumnLabel 118: * @see ResultSetMetaData#getColumnName 119: */ 120: public boolean isLabelMapMode () 121: { 122: return labelMapMode; 123: } 124: 125: /** 126: * Updates the result set in this model with the given ResultSet object. 127: * 128: * @param resultset the new result set. 129: * @throws SQLException if there is a problem with the result set. 130: */ 131: public void updateResultSet (final ResultSet resultset) 132: throws SQLException 133: { 134: if (this.resultset != null) 135: { 136: close(); 137: } 138: 139: this.resultset = resultset; 140: this.dbmd = resultset.getMetaData(); 141: 142: if (resultset.last()) 143: { 144: rowCount = resultset.getRow(); 145: } 146: else 147: { 148: rowCount = 0; 149: } 150: 151: fireTableStructureChanged(); 152: } 153: 154: /** 155: * Clears the model of the current result set. The resultset is closed. 156: */ 157: public void close () 158: { 159: // Close the old result set if needed. 160: if (resultset != null) 161: { 162: try 163: { 164: resultset.close(); 165: } 166: catch (SQLException e) 167: { 168: // Just in case the JDBC driver can't close a result set twice. 169: // e.printStackTrace(); 170: } 171: } 172: resultset = null; 173: dbmd = null; 174: rowCount = 0; 175: fireTableStructureChanged(); 176: } 177: 178: /** 179: * Get a rowCount. This can be a very expensive operation on large datasets. Returns -1 180: * if the total amount of rows is not known to the result set. 181: * 182: * @return the row count. 183: */ 184: public int getRowCount () 185: { 186: if (resultset == null) 187: { 188: return 0; 189: } 190: 191: try 192: { 193: if (resultset.last()) 194: { 195: rowCount = resultset.getRow(); 196: if (rowCount == -1) 197: { 198: rowCount = 0; 199: } 200: } 201: else 202: { 203: rowCount = 0; 204: } 205: } 206: catch (SQLException sqle) 207: { 208: //Log.debug ("GetRowCount failed, returning 0 rows", sqle); 209: return 0; 210: } 211: return rowCount; 212: } 213: 214: /** 215: * Returns the number of columns in the ResultSet. Returns 0 if no result set is set or 216: * the column count could not be retrieved. 217: * 218: * @return the column count. 219: * 220: * @see java.sql.ResultSetMetaData#getColumnCount() 221: */ 222: public int getColumnCount () 223: { 224: if (resultset == null) 225: { 226: return 0; 227: } 228: 229: if (dbmd != null) 230: { 231: try 232: { 233: return dbmd.getColumnCount(); 234: } 235: catch (SQLException e) 236: { 237: //Log.debug ("GetColumnCount failed", e); 238: } 239: } 240: return 0; 241: } 242: 243: /** 244: * Returns the columnLabel or column name for the given column. Whether the label or the 245: * name is returned depends on the label map mode. 246: * 247: * @param column the column index. 248: * @return the column name. 249: * 250: * @see java.sql.ResultSetMetaData#getColumnLabel(int) 251: */ 252: public String getColumnName (final int column) 253: { 254: if (dbmd != null) 255: { 256: try 257: { 258: if (isLabelMapMode()) 259: { 260: return dbmd.getColumnLabel(column + 1); 261: } 262: else 263: { 264: return dbmd.getColumnName(column + 1); 265: } 266: } 267: catch (SQLException e) 268: { 269: Log.info("ScrollableResultSetTableModel.getColumnName: SQLException."); 270: } 271: } 272: return null; 273: } 274: 275: /** 276: * Returns the value of the specified row and the specified column from within the 277: * resultset. 278: * 279: * @param row the row index. 280: * @param column the column index. 281: * @return the value. 282: */ 283: public Object getValueAt (final int row, final int column) 284: { 285: if (resultset != null) 286: { 287: try 288: { 289: resultset.absolute(row + 1); 290: return resultset.getObject(column + 1); 291: } 292: catch (SQLException e) 293: { 294: //Log.debug ("Query failed for [" + row + "," + column + "]", e); 295: } 296: } 297: return null; 298: } 299: 300: /** 301: * Returns the class of the resultset column. Returns Object.class if an error 302: * occurred. 303: * 304: * @param column the column index. 305: * @return the column class. 306: */ 307: public Class getColumnClass (final int column) 308: { 309: if (types != null) 310: { 311: return types[column]; 312: } 313: if (dbmd != null) 314: { 315: try 316: { 317: types = TypeMapper.mapTypes(dbmd); 318: return types[column]; 319: } 320: catch (Exception e) 321: { 322: //Log.debug ("GetColumnClass failed for " + column, e); 323: } 324: } 325: return Object.class; 326: } 327: 328: 329: /** 330: * Returns the classname of the resultset column. Returns Object.class if an error 331: * occurred. 332: * 333: * @param column the column index. 334: * @return the column class name. 335: */ 336: public String getColumnClassName (final int column) 337: { 338: if (dbmd != null) 339: { 340: return mckoiDBFixClassName(getColumnClass(column).getName()); 341: } 342: return Object.class.getName(); 343: } 344: 345: /** 346: * Just removes the word class from the start of the classname string McKoiDB version 347: * 0.92 was not able to properly return classnames of resultset elements. 348: * 349: * @param classname the class name. 350: * @return the modified class name. 351: */ 352: private String mckoiDBFixClassName (final String classname) 353: { 354: if (classname.startsWith("class ")) 355: { 356: return classname.substring(6).trim(); 357: } 358: return classname; 359: } 360: }