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: * BSFExpression.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.modules.misc.bsf;
030:
031: import java.io.IOException;
032: import java.io.ObjectInputStream;
033:
034: import org.apache.bsf.BSFException;
035: import org.apache.bsf.BSFManager;
036: import org.jfree.report.DataRow;
037: import org.jfree.report.function.AbstractExpression;
038: import org.jfree.util.Log;
039:
040: /**
041: * An expression that uses the Bean scripting framework to perform a scripted
042: * calculation.
043: *
044: * @author Thomas Morgner
045: */
046: public class BSFExpression extends AbstractExpression {
047: /**
048: * The interpreter used to evaluate the expression.
049: */
050: private transient BSFManager interpreter;
051: private transient boolean invalid;
052: private transient DataRowWrapper dataRowWrapper;
053:
054: private String language;
055: private String script;
056: private String expression;
057:
058: /**
059: * Default constructor, create a new BeanShellExpression.
060: */
061: public BSFExpression() {
062: }
063:
064: /**
065: * Creates a new interpreter instance.
066: *
067: * @return the interpreter or null, if there was an error.
068: */
069: protected BSFManager createInterpreter() {
070: try {
071: final BSFManager interpreter = new BSFManager();
072: initializeInterpreter(interpreter);
073: return interpreter;
074: } catch (Exception e) {
075: Log.error("Unable to initialize the expression", e); //$NON-NLS-1$
076: return null;
077: }
078: }
079:
080: /**
081: * Initializes the Bean-Scripting Framework manager.
082: *
083: * @param interpreter the BSF-Manager that should be initialized.
084: * @throws BSFException if an error occured.
085: */
086: protected void initializeInterpreter(final BSFManager interpreter)
087: throws BSFException {
088: dataRowWrapper = new DataRowWrapper();
089: interpreter.declareBean(
090: "dataRow", dataRowWrapper, DataRow.class); //$NON-NLS-1$
091: if (script != null) {
092: interpreter
093: .exec(getLanguage(), "script", 1, 1, getScript()); //$NON-NLS-1$
094: }
095: }
096:
097: /**
098: * Evaluates the defined expression. If an exception or an evaluation error occures, the
099: * evaluation returns null and the error is logged. The current datarow and a copy of
100: * the expressions properties are set to script-internal variables. Changes to the
101: * properties will not alter the expressions original properties and will be lost when
102: * the evaluation is finished.
103: * <p/>
104: * Expressions do not maintain a state and no assumptions about the order of evaluation
105: * can be made.
106: *
107: * @return the evaluated value or null.
108: */
109: public Object getValue() {
110: if (invalid || script == null) {
111: return null;
112: }
113: if (interpreter == null) {
114: interpreter = createInterpreter();
115: if (interpreter == null) {
116: invalid = true;
117: return null;
118: }
119: }
120: try {
121: dataRowWrapper.setParent(getDataRow());
122: return interpreter.eval(getLanguage(),
123: "expression", 1, 1, getExpression()); //$NON-NLS-1$
124: } catch (Exception e) {
125: Log.warn(new Log.SimpleMessage("Evaluation error: ", //$NON-NLS-1$
126: e.getClass(), " - ", e.getMessage()), e); //$NON-NLS-1$
127: return null;
128: }
129: }
130:
131: /**
132: * Clones the expression and reinitializes the script.
133: *
134: * @return a clone of the expression.
135: *
136: * @throws CloneNotSupportedException this should never happen.
137: */
138: public Object clone() throws CloneNotSupportedException {
139: final BSFExpression expression = (BSFExpression) super .clone();
140: expression.interpreter = null;
141: return expression;
142: }
143:
144: /**
145: * Serialisation support. The transient child elements were not saved.
146: *
147: * @param in the input stream.
148: * @throws IOException if there is an I/O error.
149: * @throws ClassNotFoundException if a serialized class is not defined on this system.
150: */
151: private void readObject(final ObjectInputStream in)
152: throws IOException, ClassNotFoundException {
153: in.defaultReadObject();
154: }
155:
156: /**
157: * Returns the script that gets evaluated every time the getValue()
158: * method is called.
159: *
160: * @return the script.
161: */
162: public String getExpression() {
163: return expression;
164: }
165:
166: /**
167: * Invalidates the interpreter-cache and forces a reinterpretation of the
168: * script.
169: */
170: protected void invalidate() {
171: this .interpreter = null;
172: }
173:
174: /**
175: * Sets the script that should be executed. Whats in the script depends on
176: * what langage is selected.
177: *
178: * @param expression the script.
179: */
180: public void setExpression(final String expression) {
181: this .expression = expression;
182: this .interpreter = null;
183: }
184:
185: /**
186: * Returns the programming language, in which the interpreter work.
187: *
188: * @return the programming language, which must be one of the supported
189: * BSF-Languages.
190: */
191: public String getLanguage() {
192: return language;
193: }
194:
195: /**
196: * Defines the programming language of the script and expression.
197: *
198: * @param language the programming language of the script.
199: */
200: public void setLanguage(final String language) {
201: this .language = language;
202: this .interpreter = null;
203: }
204:
205: /**
206: * Returns the script. The script is a predefined piece of code that gets
207: * executed once. It can (and should) be used to perform global initializations
208: * and to define functions.
209: *
210: * @return the script (can be null).
211: */
212: public String getScript() {
213: return script;
214: }
215:
216: /**
217: * Defines the script. The script is a predefined piece of code that gets
218: * executed once. It can (and should) be used to perform global initializations
219: * and to define functions.
220: *
221: * @param script an initialization script.
222: */
223: public void setScript(final String script) {
224: this.script = script;
225: this.interpreter = null;
226: }
227: }
|