Source for org.jfree.report.modules.misc.tablemodel.ResultSetTableModelFactory

   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: }