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: ReportDataRow.java 2890 2007-06-10 15:54:22Z taqua $ 027 * ------------ 028 * (C) Copyright 2000-2005, by Object Refinery Limited. 029 * (C) Copyright 2005-2007, by Pentaho Corporation. 030 */ 031 package org.jfree.report.data; 032 033 import java.util.Collections; 034 import java.util.HashMap; 035 import java.util.Map; 036 037 import org.jfree.report.DataFlags; 038 import org.jfree.report.DataRow; 039 import org.jfree.report.DataSet; 040 import org.jfree.report.DataSourceException; 041 import org.jfree.report.ReportData; 042 import org.jfree.report.ReportDataFactory; 043 import org.jfree.report.ReportDataFactoryException; 044 import org.jfree.report.util.IntegerCache; 045 import org.jfree.util.ObjectUtilities; 046 047 /** 048 * Creation-Date: 20.02.2006, 15:32:32 049 * 050 * @author Thomas Morgner 051 */ 052 public final class ReportDataRow implements DataRow 053 { 054 private Map nameCache; 055 private DataFlags[] data; 056 private ReportData reportData; 057 private int cursor; 058 059 private ReportDataRow(final ReportData reportData) throws DataSourceException 060 { 061 if (reportData == null) 062 { 063 throw new NullPointerException(); 064 } 065 066 synchronized (reportData) 067 { 068 this.reportData = reportData; 069 070 reportData.setCursorPosition(ReportData.BEFORE_FIRST_ROW); 071 final boolean readable; 072 if (reportData.isAdvanceable()) 073 { 074 readable = reportData.next() && reportData.isReadable(); 075 cursor = reportData.getCursorPosition(); 076 } 077 else 078 { 079 readable = false; 080 cursor = 0; 081 } 082 083 final HashMap nameCache = new HashMap(); 084 final int columnCount = reportData.getColumnCount(); 085 this.data = new DataFlags[columnCount]; 086 087 for (int i = 0; i < columnCount; i++) 088 { 089 final String columnName = reportData.getColumnName(i); 090 if (columnName != null) 091 { 092 nameCache.put(columnName, IntegerCache.getInteger(i)); 093 } 094 095 if (readable) 096 { 097 final Object value = reportData.get(i); 098 this.data[i] = new DefaultDataFlags(columnName, value, true); 099 } 100 else 101 { 102 this.data[i] = new DefaultDataFlags(columnName, null, true); 103 } 104 } 105 this.nameCache = Collections.unmodifiableMap(nameCache); 106 } 107 } 108 109 private ReportDataRow(final ReportData reportData, 110 final ReportDataRow reportDataRow) 111 throws DataSourceException 112 { 113 if (reportData == null) 114 { 115 throw new NullPointerException(); 116 } 117 118 if (reportDataRow == null) 119 { 120 throw new NullPointerException(); 121 } 122 123 synchronized (reportData) 124 { 125 this.reportData = reportData; 126 this.cursor = reportData.getCursorPosition(); 127 final int columnCount = reportData.getColumnCount(); 128 this.data = new DataFlags[columnCount]; 129 130 for (int i = 0; i < columnCount; i++) 131 { 132 final String columnName = reportData.getColumnName(i); 133 final Object value = reportData.get(i); 134 final boolean changed = ObjectUtilities.equal(value, reportDataRow.get(i)); 135 this.data[i] = new DefaultDataFlags(columnName, value, changed); 136 } 137 this.nameCache = reportDataRow.nameCache; 138 } 139 } 140 141 public static ReportDataRow createDataRow(final ReportDataFactory dataFactory, 142 final String query, 143 final DataSet parameters) 144 throws DataSourceException, ReportDataFactoryException 145 { 146 final ReportData reportData = dataFactory.queryData(query, parameters); 147 return new ReportDataRow(reportData); 148 } 149 150 /** 151 * Returns the value of the expression or column in the tablemodel using the given column number as index. For 152 * functions and expressions, the <code>getValue()</code> method is called and for columns from the tablemodel the 153 * tablemodel method <code>getValueAt(row, column)</code> gets called. 154 * 155 * @param col the item index. 156 * @return the value. 157 * @throws IllegalStateException if the datarow detected a deadlock. 158 */ 159 public Object get(final int col) throws DataSourceException 160 { 161 return data[col].getValue(); 162 } 163 164 /** 165 * Returns the value of the function, expression or column using its specific name. The given name is translated into 166 * a valid column number and the the column is queried. For functions and expressions, the <code>getValue()</code> 167 * method is called and for columns from the tablemodel the tablemodel method <code>getValueAt(row, column)</code> 168 * gets called. 169 * 170 * @param col the item index. 171 * @return the value. 172 * @throws IllegalStateException if the datarow detected a deadlock. 173 */ 174 public Object get(final String col) throws DataSourceException 175 { 176 final Integer colIdx = (Integer) nameCache.get(col); 177 if (colIdx == null) 178 { 179 throw new DataSourceException 180 ("Invalid name specified. There is no such column."); 181 } 182 183 return data[colIdx.intValue()].getValue(); 184 } 185 186 /** 187 * Returns the name of the column, expression or function. For columns from the tablemodel, the tablemodels 188 * <code>getColumnName</code> method is called. For functions, expressions and report properties the assigned name is 189 * returned. 190 * 191 * @param col the item index. 192 * @return the name. 193 */ 194 public String getColumnName(final int col) 195 { 196 return data[col].getName(); 197 } 198 199 /** 200 * Returns the number of columns, expressions and functions and marked ReportProperties in the report. 201 * 202 * @return the item count. 203 */ 204 public int getColumnCount() 205 { 206 return data.length; 207 } 208 209 public DataFlags getFlags(final String col) throws DataSourceException 210 { 211 final Integer colIdx = (Integer) nameCache.get(col); 212 if (colIdx == null) 213 { 214 throw new DataSourceException 215 ("Invalid name specified. There is no such column."); 216 } 217 218 return data[colIdx.intValue()]; 219 } 220 221 public DataFlags getFlags(final int col) 222 { 223 return data[col]; 224 } 225 226 /** 227 * Advances to the next row and attaches the given master row to the objects contained in that client data row. 228 * 229 * @param master 230 * @return 231 */ 232 public ReportDataRow advance() throws DataSourceException 233 { 234 synchronized (reportData) 235 { 236 if (reportData.getCursorPosition() != cursor) 237 { 238 // directly go to the position we need. 239 if (reportData.setCursorPosition(cursor + 1) == false) 240 { 241 throw new DataSourceException("Unable to advance cursor position"); 242 } 243 } 244 else 245 { 246 if (reportData.next() == false) 247 { 248 throw new DataSourceException("Unable to advance cursor position"); 249 } 250 } 251 return new ReportDataRow(reportData, this); 252 } 253 } 254 255 public boolean isAdvanceable() throws DataSourceException 256 { 257 synchronized (reportData) 258 { 259 if (reportData.getCursorPosition() != cursor) 260 { 261 // directly go to the position we need. 262 if (reportData.setCursorPosition(cursor) == false) 263 { 264 return false; 265 } 266 } 267 return reportData.isAdvanceable(); 268 } 269 } 270 271 public ReportData getReportData() 272 { 273 return reportData; 274 } 275 276 public int getCursor() 277 { 278 return cursor; 279 } 280 }