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