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: FormulaFunction.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.expressions;
031:
032: import org.jfree.formula.Formula;
033: import org.jfree.formula.FormulaContext;
034: import org.jfree.formula.parser.ParseException;
035: import org.jfree.report.DataSourceException;
036: import org.jfree.report.flow.ReportContext;
037: import org.jfree.util.Log;
038:
039: /**
040: * Creation-Date: 04.11.2006, 19:24:04
041: *
042: * @author Thomas Morgner
043: */
044: public class FormulaFunction extends AbstractExpression implements
045: Function {
046: private String formulaNamespace;
047: private String formulaExpression;
048: private String formula;
049:
050: private String initialNamespace;
051: private String initialExpression;
052: private String initial;
053: private transient Formula compiledFormula;
054: private boolean initialized;
055:
056: public FormulaFunction() {
057: }
058:
059: private synchronized FormulaContext getFormulaContext() {
060: final ReportContext globalContext = getRuntime()
061: .getReportContext();
062: return globalContext.getFormulaContext();
063: }
064:
065: public String getInitial() {
066: return initial;
067: }
068:
069: public String getInitialExpression() {
070: return initialExpression;
071: }
072:
073: public String getInitialNamespace() {
074: return initialNamespace;
075: }
076:
077: public void setInitial(final String initial) {
078: this .initial = initial;
079: if (initial == null) {
080: initialNamespace = null;
081: initialExpression = null;
082: } else {
083: final int separator = initial.indexOf(':');
084: if (separator <= 0 || ((separator + 1) == initial.length())) {
085: if (formula.startsWith("=")) {
086: initialNamespace = "report";
087: initialExpression = initial.substring(1);
088: } else {
089: // error: invalid formula.
090: initialNamespace = null;
091: initialExpression = null;
092: }
093: } else {
094: initialNamespace = initial.substring(0, separator);
095: initialExpression = initial.substring(separator + 1);
096: }
097: }
098: }
099:
100: public String getFormula() {
101: return formula;
102: }
103:
104: public String getFormulaNamespace() {
105: return formulaNamespace;
106: }
107:
108: public String getFormulaExpression() {
109: return formulaExpression;
110: }
111:
112: public void setFormula(final String formula) {
113: this .formula = formula;
114: if (formula == null) {
115: formulaNamespace = null;
116: formulaExpression = null;
117: } else {
118: final int separator = formula.indexOf(':');
119: if (separator <= 0 || ((separator + 1) == formula.length())) {
120: if (formula.startsWith("=")) {
121: formulaNamespace = "report";
122: formulaExpression = formula.substring(1);
123: } else {
124: // error: invalid formula.
125: formulaNamespace = null;
126: formulaExpression = null;
127: }
128: } else {
129: formulaNamespace = formula.substring(0, separator);
130: formulaExpression = formula.substring(separator + 1);
131: }
132: }
133: this .compiledFormula = null;
134: }
135:
136: /**
137: * When the advance method is called, the function is asked to perform the
138: * next step of its computation.
139: * <p/>
140: * The original function must not be altered during that step (or more
141: * correctly, calling advance on the original expression again must not return
142: * a different result).
143: *
144: * @return a copy of the function containing the new state.
145: */
146: public Function advance() throws DataSourceException {
147: try {
148: return (Function) clone();
149: } catch (CloneNotSupportedException e) {
150: throw new DataSourceException(
151: "Unable to derive a new instance");
152: }
153: }
154:
155: private Object computeInitialValue() {
156: try {
157: if (initial != null) {
158: final Formula initFormula = new Formula(
159: initialExpression);
160: final ReportFormulaContext context = new ReportFormulaContext(
161: getFormulaContext(), getDataRow());
162: context.setDeclaringElement(getRuntime()
163: .getDeclaringParent());
164: try {
165: initFormula.initialize(context);
166: return initFormula.evaluate();
167: } finally {
168: context.setDeclaringElement(null);
169: context.setDataRow(null);
170: }
171: }
172:
173: // if the code above did not trigger, compute a regular thing ..
174: return computeRegularValue();
175: } catch (Exception e) {
176: Log.debug("Failed to compute the initial value.");
177: return null;
178: }
179: }
180:
181: private Object computeRegularValue() {
182: try {
183: if (compiledFormula == null) {
184: compiledFormula = new Formula(formulaExpression);
185: }
186:
187: final ReportFormulaContext context = new ReportFormulaContext(
188: getFormulaContext(), getDataRow());
189: context.setDeclaringElement(getRuntime()
190: .getDeclaringParent());
191: try {
192: compiledFormula.initialize(context);
193: return compiledFormula.evaluate();
194: } finally {
195: context.setDeclaringElement(null);
196: context.setDataRow(null);
197: }
198: } catch (Exception e) {
199: Log.debug("Failed to compute the regular value.", e);
200: return null;
201: }
202: }
203:
204: /**
205: * Return the current expression value. <P> The value depends (obviously) on
206: * the expression implementation.
207: *
208: * @return the value of the function.
209: */
210: public Object computeValue() throws DataSourceException {
211: try {
212: if (initialized == false) {
213: initialized = true;
214: return computeInitialValue();
215: }
216: return computeRegularValue();
217: } catch (Exception e) {
218: return null;
219: }
220: }
221:
222: /**
223: * Clones the expression, expression should be reinitialized after the
224: * cloning. <P> Expression maintain no state, cloning is done at the beginning
225: * of the report processing to disconnect the used expression from any other
226: * object space.
227: *
228: * @return A clone of this expression.
229: * @throws CloneNotSupportedException this should never happen.
230: */
231: public Object clone() throws CloneNotSupportedException {
232: final FormulaFunction o = (FormulaFunction) super .clone();
233: if (compiledFormula != null) {
234: o.compiledFormula = (Formula) compiledFormula.clone();
235: }
236: return o;
237: }
238:
239: /**
240: * Returns the compiled formula. The formula is not connected to a formula
241: * context.
242: *
243: * @return the formula.
244: * @throws org.jfree.formula.parser.ParseException if the formula contains syntax errors.
245: */
246: public Formula getCompiledFormula() throws ParseException {
247: if (compiledFormula == null) {
248: compiledFormula = new Formula(formulaExpression);
249: }
250: return compiledFormula;
251: }
252: }
|