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: ExpressionDataRow.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.data;
031:
032: import java.util.HashMap;
033:
034: import org.jfree.report.DataFlags;
035: import org.jfree.report.DataRow;
036: import org.jfree.report.DataSourceException;
037: import org.jfree.report.flow.ReportContext;
038: import org.jfree.util.Log;
039:
040: /**
041: * A datarow for all expressions encountered in the report. This datarow is a
042: * stack-like structure, which allows easy adding and removing of expressions,
043: * even if these expressions have been cloned and or otherwisely modified.
044: *
045: * @author Thomas Morgner
046: */
047: public final class ExpressionDataRow implements DataRow {
048: private ExpressionSlot[] expressions;
049: private int length;
050: private HashMap nameCache;
051: private GlobalMasterRow masterRow;
052: private ReportContext reportContext;
053:
054: public ExpressionDataRow(final GlobalMasterRow masterRow,
055: final ReportContext reportContext, final int capacity) {
056: this .masterRow = masterRow;
057: this .nameCache = new HashMap(capacity);
058: this .expressions = new ExpressionSlot[capacity];
059: this .reportContext = reportContext;
060: }
061:
062: private ExpressionDataRow(final GlobalMasterRow masterRow,
063: final ExpressionDataRow previousRow)
064: throws CloneNotSupportedException {
065: this .reportContext = previousRow.reportContext;
066: this .masterRow = masterRow;
067: this .nameCache = (HashMap) previousRow.nameCache.clone();
068: this .expressions = new ExpressionSlot[previousRow.expressions.length];
069: this .length = previousRow.length;
070: for (int i = 0; i < length; i++) {
071: final ExpressionSlot expression = previousRow.expressions[i];
072: if (expression == null) {
073: Log.debug("Error: Expression is null...");
074: } else {
075: expressions[i] = (ExpressionSlot) expression.clone();
076: }
077: }
078: }
079:
080: private void ensureCapacity(final int requestedSize) {
081: final int capacity = this .expressions.length;
082: if (capacity > requestedSize) {
083: return;
084: }
085: final int newSize = Math.max(capacity * 2, requestedSize + 10);
086:
087: final ExpressionSlot[] newExpressions = new ExpressionSlot[newSize];
088:
089: System.arraycopy(expressions, 0, newExpressions, 0, length);
090:
091: this .expressions = newExpressions;
092: }
093:
094: /**
095: * This adds the expression to the data-row and queries the expression for the
096: * first time.
097: *
098: * @param ex
099: * @param rd
100: * @throws DataSourceException
101: */
102: public synchronized void pushExpression(
103: final ExpressionSlot expressionSlot)
104: throws DataSourceException {
105: if (expressionSlot == null) {
106: throw new NullPointerException();
107: }
108:
109: ensureCapacity(length + 1);
110:
111: this .expressions[length] = expressionSlot;
112: final String name = expressionSlot.getName();
113: if (name != null) {
114: nameCache.put(name, expressionSlot);
115: }
116: length += 1;
117:
118: expressionSlot.updateDataRow(masterRow.getGlobalView());
119: // A manual advance to initialize the function.
120: expressionSlot.advance();
121: if (name != null) {
122: final Object value = expressionSlot.getValue();
123: final MasterDataRowChangeEvent chEvent = new MasterDataRowChangeEvent(
124: MasterDataRowChangeEvent.COLUMN_ADDED, name, value);
125: masterRow.dataRowChanged(chEvent);
126: }
127: }
128:
129: public synchronized void pushExpressions(
130: final ExpressionSlot[] expressionSlots)
131: throws DataSourceException {
132: if (expressionSlots == null) {
133: throw new NullPointerException();
134: }
135:
136: ensureCapacity(length + expressionSlots.length);
137: for (int i = 0; i < expressionSlots.length; i++) {
138: final ExpressionSlot expression = expressionSlots[i];
139: if (expression == null) {
140: continue;
141: }
142: pushExpression(expression);
143: }
144: }
145:
146: public synchronized void popExpressions(final int counter)
147: throws DataSourceException {
148: for (int i = 0; i < counter; i++) {
149: popExpression();
150: }
151: }
152:
153: public synchronized void popExpression() throws DataSourceException {
154: if (length == 0) {
155: return;
156: }
157: final String originalName = expressions[length - 1].getName();
158: final boolean preserve = expressions[length - 1].isPreserve();
159: this .expressions[length - 1] = null;
160: this .length -= 1;
161: if (originalName != null) {
162: int otherIndex = -1;
163: for (int i = length - 1; i >= 0; i -= 1) {
164: final ExpressionSlot expression = expressions[i];
165: if (originalName.equals(expression.getName())) {
166: otherIndex = i;
167: break;
168: }
169: }
170: if (otherIndex == -1) {
171: nameCache.remove(originalName);
172: } else {
173: nameCache.put(originalName, expressions[otherIndex]);
174: }
175:
176: if (preserve == false) {
177: final MasterDataRowChangeEvent chEvent = new MasterDataRowChangeEvent(
178: MasterDataRowChangeEvent.COLUMN_REMOVED,
179: originalName, null);
180: masterRow.dataRowChanged(chEvent);
181: }
182: // for preserved elements we do not send an remove-event.
183: }
184:
185: }
186:
187: /**
188: * Returns the value of the expressions or column in the tablemodel using the
189: * given column number as index. For functions and expressions, the
190: * <code>getValue()</code> method is called and for columns from the
191: * tablemodel the tablemodel method <code>getValueAt(row, column)</code> gets
192: * called.
193: *
194: * @param col the item index.
195: * @return the value.
196: * @throws IllegalStateException if the datarow detected a deadlock.
197: */
198: public Object get(final int col) throws DataSourceException {
199: return expressions[col].getValue();
200: }
201:
202: /**
203: * Returns the value of the function, expressions or column using its specific
204: * name. The given name is translated into a valid column number and the the
205: * column is queried. For functions and expressions, the
206: * <code>getValue()</code> method is called and for columns from the
207: * tablemodel the tablemodel method <code>getValueAt(row, column)</code> gets
208: * called.
209: *
210: * @param col the item index.
211: * @return the value.
212: * @throws IllegalStateException if the datarow detected a deadlock.
213: */
214: public Object get(final String col) throws DataSourceException {
215: final ExpressionSlot es = (ExpressionSlot) nameCache.get(col);
216: if (es == null) {
217: return null;
218: }
219:
220: return es.getValue();
221: }
222:
223: /**
224: * Returns the name of the column, expressions or function. For columns from
225: * the tablemodel, the tablemodels <code>getColumnName</code> method is
226: * called. For functions, expressions and report properties the assigned name
227: * is returned.
228: *
229: * @param col the item index.
230: * @return the name.
231: */
232: public String getColumnName(final int col) {
233: return expressions[col].getName();
234: }
235:
236: /**
237: * Returns the number of columns, expressions and functions and marked
238: * ReportProperties in the report.
239: *
240: * @return the item count.
241: */
242: public int getColumnCount() {
243: return length;
244: }
245:
246: public DataFlags getFlags(final String col) {
247: throw new UnsupportedOperationException();
248: }
249:
250: public DataFlags getFlags(final int col) {
251: throw new UnsupportedOperationException();
252: }
253:
254: /**
255: * Advances to the next row and attaches the given master row to the objects
256: * contained in that client data row.
257: *
258: * @param master
259: * @param deepTraversing only advance expressions that have been marked as
260: * deeply traversing
261: * @return
262: */
263: public ExpressionDataRow advance(final GlobalMasterRow master,
264: final boolean deepTraversing) throws DataSourceException {
265: try {
266: final ExpressionDataRow edr = new ExpressionDataRow(master,
267: this );
268:
269: // It is defined, that new expressions get evaluated before any older
270: // expression.
271: for (int i = edr.length - 1; i >= 0; i--) {
272: final ExpressionSlot expressionSlot = edr.expressions[i];
273: expressionSlot.updateDataRow(master.getGlobalView());
274: if (deepTraversing == false
275: || (expressionSlot.isDeepTraversing())) {
276: expressionSlot.advance();
277: }
278: // Query the value (once per advance) ..
279: final Object value = expressionSlot.getValue();
280: final String name = expressionSlot.getName();
281: if (name != null) {
282: final MasterDataRowChangeEvent chEvent = new MasterDataRowChangeEvent(
283: MasterDataRowChangeEvent.COLUMN_UPDATED,
284: name, value);
285: master.dataRowChanged(chEvent);
286: }
287: }
288: return edr;
289: } catch (CloneNotSupportedException e) {
290: throw new DataSourceException("Cloning failed", e);
291: }
292: }
293:
294: public ExpressionDataRow derive(final GlobalMasterRow master)
295: throws DataSourceException {
296: try {
297: return new ExpressionDataRow(master, this );
298: } catch (CloneNotSupportedException e) {
299: throw new DataSourceException("Cloning failed", e);
300: }
301: }
302:
303: public ExpressionSlot[] getSlots() {
304: // to be totally safe from any tampering, we would have to do some sort of
305: // deep-copy here.
306: final ExpressionSlot[] slots = new ExpressionSlot[length];
307: System.arraycopy(expressions, 0, slots, 0, length);
308: return slots;
309: }
310: }
|