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: ResultSetTableModelFactory.java 3525 2007-10-16 11:43:48Z tmorgner $ 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 java.util.ArrayList; 37: import javax.swing.table.DefaultTableModel; 38: 39: import org.jfree.report.JFreeReportBoot; 40: import org.jfree.util.Log; 41: 42: /** 43: * Creates a <code>TableModel</code> which is backed up by a <code>ResultSet</code>. If 44: * the <code>ResultSet</code> is scrollable, a {@link org.jfree.report.modules.misc.tablemodel.ScrollableResultSetTableModel} 45: * is created, otherwise all data is copied from the <code>ResultSet</code> into a 46: * <code>DefaultTableModel</code>. 47: * <p/> 48: * The creation of a <code>DefaultTableModel</code> can be forced if the system property 49: * <code>"org.jfree.report.modules.misc.tablemodel.TableFactoryMode"</code> is set to 50: * <code>"simple"</code>. 51: * 52: * @author Thomas Morgner 53: */ 54: public final class ResultSetTableModelFactory 55: { 56: /** 57: * The configuration key defining how to map column names to column indices. 58: */ 59: public static final String COLUMN_NAME_MAPPING_KEY = 60: "org.jfree.report.modules.misc.tablemodel.ColumnNameMapping"; 61: 62: /** 63: * The 'ResultSet factory mode'. 64: */ 65: public static final String RESULTSET_FACTORY_MODE 66: = "org.jfree.report.modules.misc.tablemodel.TableFactoryMode"; 67: 68: /** 69: * Singleton instance of the factory. 70: */ 71: private static ResultSetTableModelFactory defaultInstance; 72: 73: /** 74: * Default constructor. This is a Singleton, use getInstance(). 75: */ 76: private ResultSetTableModelFactory () 77: { 78: } 79: 80: /** 81: * Creates a table model by using the given <code>ResultSet</code> as the backend. If 82: * the <code>ResultSet</code> is scrollable (the type is not 83: * <code>TYPE_FORWARD_ONLY</code>), an instance of {@link org.jfree.report.modules.misc.tablemodel.ScrollableResultSetTableModel} 84: * is returned. This model uses the extended capabilities of scrollable resultsets to 85: * directly read data from the database without caching or the need of copying the 86: * complete <code>ResultSet</code> into the programs memory. 87: * <p/> 88: * If the <code>ResultSet</code> lacks the scollable features, the data will be copied 89: * into a <code>DefaultTableModel</code> and the <code>ResultSet</code> gets closed. 90: * 91: * @param rs the result set. 92: * @return a closeable table model. 93: * 94: * @throws SQLException if there is a problem with the result set. 95: */ 96: public CloseableTableModel createTableModel (final ResultSet rs) 97: throws SQLException 98: { 99: return createTableModel 100: (rs, "Label".equals(JFreeReportBoot.getInstance().getGlobalConfig().getConfigProperty 101: (COLUMN_NAME_MAPPING_KEY, "Label"))); 102: } 103: 104: /** 105: * Creates a table model by using the given <code>ResultSet</code> as the backend. If 106: * the <code>ResultSet</code> is scrollable (the type is not 107: * <code>TYPE_FORWARD_ONLY</code>), an instance of {@link org.jfree.report.modules.misc.tablemodel.ScrollableResultSetTableModel} 108: * is returned. This model uses the extended capabilities of scrollable resultsets to 109: * directly read data from the database without caching or the need of copying the 110: * complete <code>ResultSet</code> into the programs memory. 111: * <p/> 112: * If the <code>ResultSet</code> lacks the scollable features, the data will be copied 113: * into a <code>DefaultTableModel</code> and the <code>ResultSet</code> gets closed. 114: * 115: * @param rs the result set. 116: * @param labelMapping defines, whether to use column names or column labels to compute 117: * the column index. 118: * @return a closeable table model. 119: * 120: * @throws SQLException if there is a problem with the result set. 121: */ 122: public CloseableTableModel createTableModel (final ResultSet rs, 123: final boolean labelMapping) 124: throws SQLException 125: { 126: // Allow for override, some jdbc drivers are buggy :( 127: final String prop = 128: JFreeReportBoot.getInstance().getGlobalConfig().getConfigProperty 129: (RESULTSET_FACTORY_MODE, ""); 130: 131: if ("simple".equalsIgnoreCase(prop)) 132: { 133: return generateDefaultTableModel(rs, labelMapping); 134: } 135: 136: int resultSetType = ResultSet.TYPE_FORWARD_ONLY; 137: try 138: { 139: resultSetType = rs.getType(); 140: } 141: catch (SQLException sqle) 142: { 143: Log.info 144: ("ResultSet type could not be determined, assuming default table model."); 145: } 146: if (resultSetType == ResultSet.TYPE_FORWARD_ONLY) 147: { 148: return generateDefaultTableModel(rs, labelMapping); 149: } 150: else 151: { 152: return new ScrollableResultSetTableModel(rs, labelMapping); 153: } 154: } 155: 156: /** 157: * A DefaultTableModel that implements the CloseableTableModel interface. 158: */ 159: private static final class CloseableDefaultTableModel extends DefaultTableModel 160: implements CloseableTableModel 161: { 162: /** 163: * The results set. 164: */ 165: private final ResultSet res; 166: 167: /** 168: * Creates a new closeable table model. 169: * 170: * @param objects the table data. 171: * @param objects1 the column names. 172: * @param res the result set. 173: */ 174: private CloseableDefaultTableModel (final Object[][] objects, 175: final Object[] objects1, final ResultSet res) 176: { 177: super(objects, objects1); 178: this.res = res; 179: } 180: 181: /** 182: * If this model has a resultset assigned, close it, if this is a DefaultTableModel, 183: * remove all data. 184: */ 185: public void close () 186: { 187: setDataVector(new Object[0][0], new Object[0]); 188: try 189: { 190: res.close(); 191: } 192: catch (Exception e) 193: { 194: //Log.debug ("Close failed for resultset table model", e); 195: } 196: } 197: } 198: 199: /** 200: * Generates a <code>TableModel</code> that gets its contents filled from a 201: * <code>ResultSet</code>. The column names of the <code>ResultSet</code> will form the 202: * column names of the table model. 203: * <p/> 204: * Hint: To customize the names of the columns, use the SQL column aliasing (done with 205: * <code>SELECT nativecolumnname AS "JavaColumnName" FROM ....</code> 206: * 207: * @param rs the result set. 208: * @return a closeable table model. 209: * 210: * @throws SQLException if there is a problem with the result set. 211: */ 212: public CloseableTableModel generateDefaultTableModel (final ResultSet rs) 213: throws SQLException 214: { 215: return generateDefaultTableModel(rs, 216: "Label".equals(JFreeReportBoot.getInstance().getGlobalConfig().getConfigProperty 217: (COLUMN_NAME_MAPPING_KEY, "Label"))); 218: } 219: 220: /** 221: * Generates a <code>TableModel</code> that gets its contents filled from a 222: * <code>ResultSet</code>. The column names of the <code>ResultSet</code> will form the 223: * column names of the table model. 224: * <p/> 225: * Hint: To customize the names of the columns, use the SQL column aliasing (done with 226: * <code>SELECT nativecolumnname AS "JavaColumnName" FROM ....</code> 227: * 228: * @param rs the result set. 229: * @param labelMapping defines, whether to use column names or column labels to compute 230: * the column index. 231: * @return a closeable table model. 232: * 233: * @throws SQLException if there is a problem with the result set. 234: */ 235: public CloseableTableModel generateDefaultTableModel 236: (final ResultSet rs, final boolean labelMapping) 237: throws SQLException 238: { 239: final ResultSetMetaData rsmd = rs.getMetaData(); 240: final int colcount = rsmd.getColumnCount(); 241: final ArrayList header = new ArrayList(colcount); 242: for (int i = 0; i < colcount; i++) 243: { 244: if (labelMapping) 245: { 246: final String name = rsmd.getColumnLabel(i + 1); 247: header.add(name); 248: } 249: else 250: { 251: final String name = rsmd.getColumnName(i + 1); 252: header.add(name); 253: } 254: } 255: final ArrayList rows = new ArrayList(); 256: while (rs.next()) 257: { 258: final Object[] column = new Object[colcount]; 259: for (int i = 0; i < colcount; i++) 260: { 261: final Object val = rs.getObject(i + 1); 262: column[i] = val; 263: } 264: rows.add(column); 265: } 266: 267: final Object[] tempRows = rows.toArray(); 268: final Object[][] rowMap = new Object[tempRows.length][]; 269: for (int i = 0; i < tempRows.length; i++) 270: { 271: rowMap[i] = (Object[]) tempRows[i]; 272: } 273: final CloseableDefaultTableModel model = 274: new CloseableDefaultTableModel(rowMap, header.toArray(), rs); 275: for (int i = 0; i < colcount; i++) 276: { 277: } 278: return model; 279: } 280: 281: /** 282: * Returns the singleton instance of the factory. 283: * 284: * @return an instance of this factory. 285: */ 286: public static synchronized ResultSetTableModelFactory getInstance () 287: { 288: if (defaultInstance == null) 289: { 290: defaultInstance = new ResultSetTableModelFactory(); 291: } 292: return defaultInstance; 293: } 294: 295: }