001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, 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: * FormulaExpression.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.function;
030:
031: import org.jfree.formula.Formula;
032: import org.jfree.formula.FormulaContext;
033: import org.jfree.util.Configuration;
034: import org.jfree.util.Log;
035:
036: /**
037: * The formula expression is used to evaluate a LibFormula/OpenFormula expression. There is generally no need to
038: * reference this class directly, as this expression is used automatically if a formula is specified in a element,
039: * style-expression or common expression.
040: *
041: * @author Thomas Morgner
042: */
043: public final class FormulaExpression extends AbstractExpression {
044: /** A cached version of the compiled formula. */
045: private transient Formula compiledFormula;
046: /** The formula namespace as defined by OpenFormula. */
047: private String formulaNamespace;
048: /** The formula itself. */
049: private String formulaExpression;
050: /** The formula as specified by the user. This is the formula and the namespace.*/
051: private String formula;
052: /** A flag indicating that the formula cannot be parsed. */
053: private boolean formulaError;
054:
055: /**
056: * Default Constructor.
057: */
058: public FormulaExpression() {
059: }
060:
061: /**
062: * Returns the defined formula context from the report processing context.
063: *
064: * @return the formula context.
065: */
066: private FormulaContext getFormulaContext() {
067: final ProcessingContext globalContext = getRuntime()
068: .getProcessingContext();
069: return globalContext.getFormulaContext();
070: }
071:
072: /**
073: * Returns the formula (incuding the optional namespace) as defined by the OpenFormula standard.
074: *
075: * @return the formula as text.
076: */
077: public String getFormula() {
078: return formula;
079: }
080:
081: /**
082: * Returns the formula namespace. If the formula specified by the user starts with "=", then the namespace
083: * "report" is assumed.
084: *
085: * @return the namespace of the formula.
086: */
087: public String getFormulaNamespace() {
088: return formulaNamespace;
089: }
090:
091: /**
092: * Returns the formula expression.
093: *
094: * @return the formula expression.
095: */
096: public String getFormulaExpression() {
097: return formulaExpression;
098: }
099:
100: /**
101: * Defines the formula (incuding the optional namespace) as defined by the OpenFormula standard.
102: *
103: * @param formula the formula as text.
104: */
105: public void setFormula(final String formula) {
106: this .formula = formula;
107: if (formula == null) {
108: formulaNamespace = null;
109: formulaExpression = null;
110: } else if (formula.length() > 0 && formula.charAt(0) == '=') {
111: formulaNamespace = "report";
112: formulaExpression = formula.substring(1);
113: } else {
114: final int separator = formula.indexOf(':');
115: if (separator <= 0 || ((separator + 1) == formula.length())) {
116: // error: invalid formula.
117: formulaNamespace = null;
118: formulaExpression = null;
119: } else {
120: formulaNamespace = formula.substring(0, separator);
121: formulaExpression = formula.substring(separator + 1);
122: }
123: }
124: this .compiledFormula = null;
125: this .formulaError = false;
126: }
127:
128: /**
129: * Computes the value of the formula by evaluating the formula against the current data-row.
130: *
131: * @return the computed value or null, if an error occured.
132: */
133: private Object computeRegularValue() {
134: if (formulaError) {
135: return null;
136: }
137:
138: if (formulaExpression == null) {
139: return null;
140: }
141:
142: try {
143: if (compiledFormula == null) {
144: compiledFormula = new Formula(formulaExpression);
145: }
146:
147: final ReportFormulaContext context = new ReportFormulaContext(
148: getFormulaContext(), getDataRow(), getRuntime()
149: .getExportDescriptor());
150: try {
151: compiledFormula.initialize(context);
152: return compiledFormula.evaluate();
153: } finally {
154: context.setDataRow(null);
155: }
156: } catch (Exception e) {
157: formulaError = true;
158: final Configuration config = getReportConfiguration();
159: if (Log.isDebugEnabled()) {
160: if ("true"
161: .equals(config
162: .getConfigProperty("org.jfree.report.function.LogFormulaFailureCause"))) {
163: Log.debug("Failed to compute the regular value ["
164: + formulaExpression + ']', e);
165: } else {
166: Log.debug("Failed to compute the regular value ["
167: + formulaExpression + ']');
168: }
169: }
170: return null;
171: }
172: }
173:
174: /**
175: * Return the computed value of the formula.
176: *
177: * @return the value of the function.
178: */
179: public Object getValue() {
180: try {
181: return computeRegularValue();
182: } catch (Exception e) {
183: return null;
184: }
185: }
186:
187: /**
188: * Clones the expression.
189: *
190: * @return A clone of this expression.
191: * @throws CloneNotSupportedException this should never happen.
192: */
193: public Object clone() throws CloneNotSupportedException {
194: final FormulaExpression o = (FormulaExpression) super .clone();
195: if (compiledFormula != null) {
196: o.compiledFormula = (Formula) compiledFormula.clone();
197: }
198: return o;
199: }
200: }
|