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: ResultSetTableModelFactory.java 3525 2007-10-16 11:43:48Z 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 java.util.ArrayList;
036: import javax.swing.table.DefaultTableModel;
037:
038: import org.jfree.report.JFreeReportBoot;
039: import org.jfree.util.Log;
040:
041: /**
042: * Creates a <code>TableModel</code> which is backed up by a <code>ResultSet</code>. If
043: * the <code>ResultSet</code> is scrollable, a {@link org.jfree.report.modules.misc.tablemodel.ScrollableResultSetTableModel}
044: * is created, otherwise all data is copied from the <code>ResultSet</code> into a
045: * <code>DefaultTableModel</code>.
046: * <p/>
047: * The creation of a <code>DefaultTableModel</code> can be forced if the system property
048: * <code>"org.jfree.report.modules.misc.tablemodel.TableFactoryMode"</code> is set to
049: * <code>"simple"</code>.
050: *
051: * @author Thomas Morgner
052: */
053: public final class ResultSetTableModelFactory {
054: /**
055: * The configuration key defining how to map column names to column indices.
056: */
057: public static final String COLUMN_NAME_MAPPING_KEY = "org.jfree.report.modules.misc.tablemodel.ColumnNameMapping";
058:
059: /**
060: * The 'ResultSet factory mode'.
061: */
062: public static final String RESULTSET_FACTORY_MODE = "org.jfree.report.modules.misc.tablemodel.TableFactoryMode";
063:
064: /**
065: * Singleton instance of the factory.
066: */
067: private static ResultSetTableModelFactory defaultInstance;
068:
069: /**
070: * Default constructor. This is a Singleton, use getInstance().
071: */
072: private ResultSetTableModelFactory() {
073: }
074:
075: /**
076: * Creates a table model by using the given <code>ResultSet</code> as the backend. If
077: * the <code>ResultSet</code> is scrollable (the type is not
078: * <code>TYPE_FORWARD_ONLY</code>), an instance of {@link org.jfree.report.modules.misc.tablemodel.ScrollableResultSetTableModel}
079: * is returned. This model uses the extended capabilities of scrollable resultsets to
080: * directly read data from the database without caching or the need of copying the
081: * complete <code>ResultSet</code> into the programs memory.
082: * <p/>
083: * If the <code>ResultSet</code> lacks the scollable features, the data will be copied
084: * into a <code>DefaultTableModel</code> and the <code>ResultSet</code> gets closed.
085: *
086: * @param rs the result set.
087: * @return a closeable table model.
088: *
089: * @throws SQLException if there is a problem with the result set.
090: */
091: public CloseableTableModel createTableModel(final ResultSet rs)
092: throws SQLException {
093: return createTableModel(rs, "Label".equals(JFreeReportBoot
094: .getInstance().getGlobalConfig().getConfigProperty(
095: COLUMN_NAME_MAPPING_KEY, "Label")));
096: }
097:
098: /**
099: * Creates a table model by using the given <code>ResultSet</code> as the backend. If
100: * the <code>ResultSet</code> is scrollable (the type is not
101: * <code>TYPE_FORWARD_ONLY</code>), an instance of {@link org.jfree.report.modules.misc.tablemodel.ScrollableResultSetTableModel}
102: * is returned. This model uses the extended capabilities of scrollable resultsets to
103: * directly read data from the database without caching or the need of copying the
104: * complete <code>ResultSet</code> into the programs memory.
105: * <p/>
106: * If the <code>ResultSet</code> lacks the scollable features, the data will be copied
107: * into a <code>DefaultTableModel</code> and the <code>ResultSet</code> gets closed.
108: *
109: * @param rs the result set.
110: * @param labelMapping defines, whether to use column names or column labels to compute
111: * the column index.
112: * @return a closeable table model.
113: *
114: * @throws SQLException if there is a problem with the result set.
115: */
116: public CloseableTableModel createTableModel(final ResultSet rs,
117: final boolean labelMapping) throws SQLException {
118: // Allow for override, some jdbc drivers are buggy :(
119: final String prop = JFreeReportBoot.getInstance()
120: .getGlobalConfig().getConfigProperty(
121: RESULTSET_FACTORY_MODE, "");
122:
123: if ("simple".equalsIgnoreCase(prop)) {
124: return generateDefaultTableModel(rs, labelMapping);
125: }
126:
127: int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
128: try {
129: resultSetType = rs.getType();
130: } catch (SQLException sqle) {
131: Log
132: .info("ResultSet type could not be determined, assuming default table model.");
133: }
134: if (resultSetType == ResultSet.TYPE_FORWARD_ONLY) {
135: return generateDefaultTableModel(rs, labelMapping);
136: } else {
137: return new ScrollableResultSetTableModel(rs, labelMapping);
138: }
139: }
140:
141: /**
142: * A DefaultTableModel that implements the CloseableTableModel interface.
143: */
144: private static final class CloseableDefaultTableModel extends
145: DefaultTableModel implements CloseableTableModel {
146: /**
147: * The results set.
148: */
149: private final ResultSet res;
150:
151: /**
152: * Creates a new closeable table model.
153: *
154: * @param objects the table data.
155: * @param objects1 the column names.
156: * @param res the result set.
157: */
158: private CloseableDefaultTableModel(final Object[][] objects,
159: final Object[] objects1, final ResultSet res) {
160: super (objects, objects1);
161: this .res = res;
162: }
163:
164: /**
165: * If this model has a resultset assigned, close it, if this is a DefaultTableModel,
166: * remove all data.
167: */
168: public void close() {
169: setDataVector(new Object[0][0], new Object[0]);
170: try {
171: res.close();
172: } catch (Exception e) {
173: //Log.debug ("Close failed for resultset table model", e);
174: }
175: }
176: }
177:
178: /**
179: * Generates a <code>TableModel</code> that gets its contents filled from a
180: * <code>ResultSet</code>. The column names of the <code>ResultSet</code> will form the
181: * column names of the table model.
182: * <p/>
183: * Hint: To customize the names of the columns, use the SQL column aliasing (done with
184: * <code>SELECT nativecolumnname AS "JavaColumnName" FROM ....</code>
185: *
186: * @param rs the result set.
187: * @return a closeable table model.
188: *
189: * @throws SQLException if there is a problem with the result set.
190: */
191: public CloseableTableModel generateDefaultTableModel(
192: final ResultSet rs) throws SQLException {
193: return generateDefaultTableModel(rs, "Label"
194: .equals(JFreeReportBoot.getInstance().getGlobalConfig()
195: .getConfigProperty(COLUMN_NAME_MAPPING_KEY,
196: "Label")));
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: * @param labelMapping defines, whether to use column names or column labels to compute
209: * the column index.
210: * @return a closeable table model.
211: *
212: * @throws SQLException if there is a problem with the result set.
213: */
214: public CloseableTableModel generateDefaultTableModel(
215: final ResultSet rs, final boolean labelMapping)
216: throws SQLException {
217: final ResultSetMetaData rsmd = rs.getMetaData();
218: final int colcount = rsmd.getColumnCount();
219: final ArrayList header = new ArrayList(colcount);
220: for (int i = 0; i < colcount; i++) {
221: if (labelMapping) {
222: final String name = rsmd.getColumnLabel(i + 1);
223: header.add(name);
224: } else {
225: final String name = rsmd.getColumnName(i + 1);
226: header.add(name);
227: }
228: }
229: final ArrayList rows = new ArrayList();
230: while (rs.next()) {
231: final Object[] column = new Object[colcount];
232: for (int i = 0; i < colcount; i++) {
233: final Object val = rs.getObject(i + 1);
234: column[i] = val;
235: }
236: rows.add(column);
237: }
238:
239: final Object[] tempRows = rows.toArray();
240: final Object[][] rowMap = new Object[tempRows.length][];
241: for (int i = 0; i < tempRows.length; i++) {
242: rowMap[i] = (Object[]) tempRows[i];
243: }
244: final CloseableDefaultTableModel model = new CloseableDefaultTableModel(
245: rowMap, header.toArray(), rs);
246: for (int i = 0; i < colcount; i++) {
247: }
248: return model;
249: }
250:
251: /**
252: * Returns the singleton instance of the factory.
253: *
254: * @return an instance of this factory.
255: */
256: public static synchronized ResultSetTableModelFactory getInstance() {
257: if (defaultInstance == null) {
258: defaultInstance = new ResultSetTableModelFactory();
259: }
260: return defaultInstance;
261: }
262:
263: }
|