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: CachingReportDataFactory.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.Arrays;
033: import java.util.HashMap;
034: import java.util.Iterator;
035:
036: import org.jfree.report.DataSet;
037: import org.jfree.report.DataSourceException;
038: import org.jfree.report.ReportData;
039: import org.jfree.report.ReportDataFactory;
040: import org.jfree.report.ReportDataFactoryException;
041:
042: /**
043: * Creation-Date: 19.11.2006, 13:35:45
044: *
045: * @author Thomas Morgner
046: */
047: public class CachingReportDataFactory implements ReportDataFactory {
048: private static class Parameters implements DataSet {
049: private Object[] dataStore;
050: private String[] nameStore;
051: private Integer hashCode;
052:
053: protected Parameters(final DataSet dataSet)
054: throws DataSourceException {
055: final int columnCount = dataSet.getColumnCount();
056: dataStore = new Object[columnCount];
057: nameStore = new String[columnCount];
058:
059: for (int i = 0; i < columnCount; i++) {
060: nameStore[i] = dataSet.getColumnName(i);
061: dataStore[i] = dataSet.get(i);
062: }
063: }
064:
065: public int getColumnCount() throws DataSourceException {
066: return dataStore.length;
067: }
068:
069: public String getColumnName(final int column)
070: throws DataSourceException {
071: return nameStore[column];
072: }
073:
074: public Object get(final int column) throws DataSourceException {
075: return dataStore[column];
076: }
077:
078: public boolean equals(final Object o) {
079: if (this == o) {
080: return true;
081: }
082: if (o == null || getClass() != o.getClass()) {
083: return false;
084: }
085:
086: final Parameters that = (Parameters) o;
087:
088: if (!Arrays.equals(dataStore, that.dataStore)) {
089: return false;
090: }
091: if (!Arrays.equals(nameStore, that.nameStore)) {
092: return false;
093: }
094:
095: return true;
096: }
097:
098: public synchronized int hashCode() {
099: if (hashCode != null) {
100: return hashCode.intValue();
101: }
102: int hashCode = 0;
103: for (int i = 0; i < dataStore.length; i++) {
104: final Object o = dataStore[i];
105: if (o != null) {
106: hashCode = hashCode * 23 + o.hashCode();
107: } else {
108: hashCode = hashCode * 23;
109: }
110: }
111: for (int i = 0; i < nameStore.length; i++) {
112: final Object o = nameStore[i];
113: if (o != null) {
114: hashCode = hashCode * 23 + o.hashCode();
115: } else {
116: hashCode = hashCode * 23;
117: }
118: }
119: this .hashCode = new Integer(hashCode);
120: return hashCode;
121: }
122: }
123:
124: private HashMap queryCache;
125:
126: private ReportDataFactory backend;
127:
128: public CachingReportDataFactory(final ReportDataFactory backend) {
129: if (backend == null) {
130: throw new NullPointerException();
131: }
132: this .backend = backend;
133: this .queryCache = new HashMap();
134: }
135:
136: public void open() {
137: backend.open();
138: }
139:
140: /**
141: * Queries a datasource. The string 'query' defines the name of the query. The Parameterset given here may contain
142: * more data than actually needed.
143: * <p/>
144: * The dataset may change between two calls, do not assume anything!
145: *
146: * @param query
147: * @param parameters
148: * @return
149: */
150: public ReportData queryData(final String query,
151: final DataSet parameters) throws ReportDataFactoryException {
152: try {
153: final HashMap parameterCache = (HashMap) queryCache
154: .get(query);
155: if (parameterCache == null) {
156: // totally new query here.
157: final HashMap newParams = new HashMap();
158: queryCache.put(query, newParams);
159:
160: final Parameters params = new Parameters(parameters);
161: final ReportData newData = backend.queryData(query,
162: params);
163: newParams.put(params, newData);
164: newData.setCursorPosition(ReportData.BEFORE_FIRST_ROW);
165: return newData;
166: } else {
167: // Lookup the parameters ...
168: final Parameters params = new Parameters(parameters);
169: final ReportData data = (ReportData) parameterCache
170: .get(params);
171: if (data != null) {
172: data.setCursorPosition(ReportData.BEFORE_FIRST_ROW);
173: return data;
174: }
175:
176: final ReportData newData = backend.queryData(query,
177: params);
178: parameterCache.put(params, newData);
179: newData.setCursorPosition(ReportData.BEFORE_FIRST_ROW);
180: return newData;
181: }
182: } catch (DataSourceException e) {
183: e.printStackTrace();
184: throw new ReportDataFactoryException(
185: "Failed to query data", e);
186: }
187: }
188:
189: /**
190: * Closes the report data factory and all report data instances that have been returned by this instance.
191: */
192: public void close() {
193: final Iterator queries = queryCache.values().iterator();
194: while (queries.hasNext()) {
195: final HashMap map = (HashMap) queries.next();
196: final Iterator dataSets = map.values().iterator();
197: while (dataSets.hasNext()) {
198: final ReportData data = (ReportData) dataSets.next();
199: try {
200: data.close();
201: } catch (DataSourceException e) {
202: // ignore, we'll finish up anyway ..
203: }
204: }
205: }
206: backend.close();
207: }
208:
209: /**
210: * Derives a freshly initialized report data factory, which is independend of the original data factory. Opening or
211: * Closing one data factory must not affect the other factories.
212: *
213: * @return
214: */
215: public ReportDataFactory derive() {
216: // If you see that exception, then you've probably tried to use that
217: // datafactory from outside of the report processing. You deserve the
218: // exception in that case ..
219: throw new UnsupportedOperationException(
220: "The CachingReportDataFactory cannot be derived.");
221: }
222: }
|