001: /**
002: * ========================================
003: * JFreeReport : a free Java report library
004: * ========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * $Id: ScrollableResultSetTableModel.java 3048 2007-07-28 18:02:42Z tmorgner $
027: * ------------
028: * (C) Copyright 2000-2005, by Object Refinery Limited.
029: * (C) Copyright 2005-2007, by Pentaho Corporation.
030: */package org.jfree.report.modules.misc.tablemodel;
031:
032: import java.sql.ResultSet;
033: import java.sql.ResultSetMetaData;
034: import java.sql.SQLException;
035: import javax.swing.table.AbstractTableModel;
036:
037: import org.jfree.util.Log;
038:
039: /**
040: * A tableModel which is backed up by a java.sql.ResultSet. Use this to directly feed your
041: * database data into JFreeReport. If you have trouble using this TableModel and you have
042: * either enough memory or your query result is not huge, you may want to use
043: * <code>ResultSetTableModelFactory.generateDefaultTableModel (ResultSet rs)</code>. That
044: * implementation will read all data from the given ResultSet and keep that data in
045: * memory.
046: * <p/>
047: * Use the close() function to close the ResultSet contained in this model.
048: *
049: * @author Thomas Morgner
050: */
051: public class ScrollableResultSetTableModel extends AbstractTableModel
052: implements CloseableTableModel {
053: /**
054: * The scrollable ResultSet source.
055: */
056: private ResultSet resultset;
057: /**
058: * The ResultSetMetaData object for this result set.
059: */
060: private ResultSetMetaData dbmd;
061: /**
062: * The number of rows in the result set.
063: */
064: private int rowCount;
065: /**
066: * Defines the column naming mode.
067: */
068: private final boolean labelMapMode;
069: /**
070: * The column types as read from the result set.
071: */
072: private Class[] types;
073:
074: /**
075: * Constructs the model.
076: *
077: * @param resultset the result set.
078: * @param labelMapMode defines, whether to use column names or column labels to compute
079: * the column index.
080: * @throws SQLException if there is a problem with the result set.
081: */
082: public ScrollableResultSetTableModel(final ResultSet resultset,
083: final boolean labelMapMode) throws SQLException {
084: this .labelMapMode = labelMapMode;
085: if (resultset != null) {
086: updateResultSet(resultset);
087: } else {
088: close();
089: }
090: }
091:
092: /**
093: * Creates a new scrollable result set with no resultset assigned and the specified
094: * label map mode.
095: *
096: * @param labelMapMode defines, whether to use column names or column labels to compute
097: * the column index.
098: */
099: protected ScrollableResultSetTableModel(final boolean labelMapMode) {
100: this .labelMapMode = labelMapMode;
101: }
102:
103: /**
104: * Returns the column name mode used to map column names into column indices. If true,
105: * then the Label is used, else the Name is used.
106: *
107: * @return true, if the column label is used for the mapping, false otherwise.
108: *
109: * @see ResultSetMetaData#getColumnLabel
110: * @see ResultSetMetaData#getColumnName
111: */
112: public boolean isLabelMapMode() {
113: return labelMapMode;
114: }
115:
116: /**
117: * Updates the result set in this model with the given ResultSet object.
118: *
119: * @param resultset the new result set.
120: * @throws SQLException if there is a problem with the result set.
121: */
122: public void updateResultSet(final ResultSet resultset)
123: throws SQLException {
124: if (this .resultset != null) {
125: close();
126: }
127:
128: this .resultset = resultset;
129: this .dbmd = resultset.getMetaData();
130:
131: if (resultset.last()) {
132: rowCount = resultset.getRow();
133: } else {
134: rowCount = 0;
135: }
136:
137: fireTableStructureChanged();
138: }
139:
140: /**
141: * Clears the model of the current result set. The resultset is closed.
142: */
143: public void close() {
144: // Close the old result set if needed.
145: if (resultset != null) {
146: try {
147: resultset.close();
148: } catch (SQLException e) {
149: // Just in case the JDBC driver can't close a result set twice.
150: // e.printStackTrace();
151: }
152: }
153: resultset = null;
154: dbmd = null;
155: rowCount = 0;
156: fireTableStructureChanged();
157: }
158:
159: /**
160: * Get a rowCount. This can be a very expensive operation on large datasets. Returns -1
161: * if the total amount of rows is not known to the result set.
162: *
163: * @return the row count.
164: */
165: public int getRowCount() {
166: if (resultset == null) {
167: return 0;
168: }
169:
170: try {
171: if (resultset.last()) {
172: rowCount = resultset.getRow();
173: if (rowCount == -1) {
174: rowCount = 0;
175: }
176: } else {
177: rowCount = 0;
178: }
179: } catch (SQLException sqle) {
180: //Log.debug ("GetRowCount failed, returning 0 rows", sqle);
181: return 0;
182: }
183: return rowCount;
184: }
185:
186: /**
187: * Returns the number of columns in the ResultSet. Returns 0 if no result set is set or
188: * the column count could not be retrieved.
189: *
190: * @return the column count.
191: *
192: * @see java.sql.ResultSetMetaData#getColumnCount()
193: */
194: public int getColumnCount() {
195: if (resultset == null) {
196: return 0;
197: }
198:
199: if (dbmd != null) {
200: try {
201: return dbmd.getColumnCount();
202: } catch (SQLException e) {
203: //Log.debug ("GetColumnCount failed", e);
204: }
205: }
206: return 0;
207: }
208:
209: /**
210: * Returns the columnLabel or column name for the given column. Whether the label or the
211: * name is returned depends on the label map mode.
212: *
213: * @param column the column index.
214: * @return the column name.
215: *
216: * @see java.sql.ResultSetMetaData#getColumnLabel(int)
217: */
218: public String getColumnName(final int column) {
219: if (dbmd != null) {
220: try {
221: if (isLabelMapMode()) {
222: return dbmd.getColumnLabel(column + 1);
223: } else {
224: return dbmd.getColumnName(column + 1);
225: }
226: } catch (SQLException e) {
227: Log
228: .info("ScrollableResultSetTableModel.getColumnName: SQLException.");
229: }
230: }
231: return null;
232: }
233:
234: /**
235: * Returns the value of the specified row and the specified column from within the
236: * resultset.
237: *
238: * @param row the row index.
239: * @param column the column index.
240: * @return the value.
241: */
242: public Object getValueAt(final int row, final int column) {
243: if (resultset != null) {
244: try {
245: resultset.absolute(row + 1);
246: return resultset.getObject(column + 1);
247: } catch (SQLException e) {
248: //Log.debug ("Query failed for [" + row + "," + column + "]", e);
249: }
250: }
251: return null;
252: }
253:
254: /**
255: * Returns the class of the resultset column. Returns Object.class if an error
256: * occurred.
257: *
258: * @param column the column index.
259: * @return the column class.
260: */
261: public Class getColumnClass(final int column) {
262: if (types != null) {
263: return types[column];
264: }
265: if (dbmd != null) {
266: try {
267: types = TypeMapper.mapTypes(dbmd);
268: return types[column];
269: } catch (Exception e) {
270: //Log.debug ("GetColumnClass failed for " + column, e);
271: }
272: }
273: return Object.class;
274: }
275:
276: /**
277: * Returns the classname of the resultset column. Returns Object.class if an error
278: * occurred.
279: *
280: * @param column the column index.
281: * @return the column class name.
282: */
283: public String getColumnClassName(final int column) {
284: if (dbmd != null) {
285: return mckoiDBFixClassName(getColumnClass(column).getName());
286: }
287: return Object.class.getName();
288: }
289:
290: /**
291: * Just removes the word class from the start of the classname string McKoiDB version
292: * 0.92 was not able to properly return classnames of resultset elements.
293: *
294: * @param classname the class name.
295: * @return the modified class name.
296: */
297: private String mckoiDBFixClassName(final String classname) {
298: if (classname.startsWith("class ")) {
299: return classname.substring(6).trim();
300: }
301: return classname;
302: }
303: }
|