Source for org.jfree.report.expressions.FormulaFunction

   1: /**
   2:  * ========================================
   3:  * JFreeReport : a free Java report library
   4:  * ========================================
   5:  *
   6:  * Project Info:  http://reporting.pentaho.org/
   7:  *
   8:  * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
   9:  *
  10:  * This library is free software; you can redistribute it and/or modify it under the terms
  11:  * of the GNU Lesser General Public License as published by the Free Software Foundation;
  12:  * either version 2.1 of the License, or (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  15:  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16:  * See the GNU Lesser General Public License for more details.
  17:  *
  18:  * You should have received a copy of the GNU Lesser General Public License along with this
  19:  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  20:  * Boston, MA 02111-1307, USA.
  21:  *
  22:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  23:  * in the United States and other countries.]
  24:  *
  25:  * ------------
  26:  * $Id: FormulaFunction.java 2725 2007-04-01 18:49:29Z taqua $
  27:  * ------------
  28:  * (C) Copyright 2000-2005, by Object Refinery Limited.
  29:  * (C) Copyright 2005-2007, by Pentaho Corporation.
  30:  */
  31: package org.jfree.report.expressions;
  32: 
  33: import org.jfree.formula.Formula;
  34: import org.jfree.formula.FormulaContext;
  35: import org.jfree.formula.parser.ParseException;
  36: import org.jfree.report.DataSourceException;
  37: import org.jfree.report.flow.ReportContext;
  38: import org.jfree.util.Log;
  39: 
  40: /**
  41:  * Creation-Date: 04.11.2006, 19:24:04
  42:  *
  43:  * @author Thomas Morgner
  44:  */
  45: public class FormulaFunction extends AbstractExpression implements Function
  46: {
  47:   private String formulaNamespace;
  48:   private String formulaExpression;
  49:   private String formula;
  50: 
  51:   private String initialNamespace;
  52:   private String initialExpression;
  53:   private String initial;
  54:   private transient Formula compiledFormula;
  55:   private boolean initialized;
  56: 
  57:   public FormulaFunction()
  58:   {
  59:   }
  60: 
  61:   private synchronized FormulaContext getFormulaContext()
  62:   {
  63:     final ReportContext globalContext = getRuntime().getReportContext();
  64:     return globalContext.getFormulaContext();
  65:   }
  66: 
  67:   public String getInitial()
  68:   {
  69:     return initial;
  70:   }
  71: 
  72:   public String getInitialExpression()
  73:   {
  74:     return initialExpression;
  75:   }
  76: 
  77:   public String getInitialNamespace()
  78:   {
  79:     return initialNamespace;
  80:   }
  81: 
  82:   public void setInitial(final String initial)
  83:   {
  84:     this.initial = initial;
  85:     if (initial == null)
  86:     {
  87:       initialNamespace = null;
  88:       initialExpression = null;
  89:     }
  90:     else
  91:     {
  92:       final int separator = initial.indexOf(':');
  93:       if (separator <= 0 || ((separator + 1) == initial.length()))
  94:       {
  95:         if (formula.startsWith("="))
  96:         {
  97:           initialNamespace = "report";
  98:           initialExpression = initial.substring(1);
  99:         }
 100:         else
 101:         {
 102:           // error: invalid formula.
 103:           initialNamespace = null;
 104:           initialExpression = null;
 105:         }
 106:       }
 107:       else
 108:       {
 109:         initialNamespace = initial.substring(0, separator);
 110:         initialExpression = initial.substring(separator + 1);
 111:       }
 112:     }
 113:   }
 114: 
 115: 
 116:   public String getFormula()
 117:   {
 118:     return formula;
 119:   }
 120: 
 121:   public String getFormulaNamespace()
 122:   {
 123:     return formulaNamespace;
 124:   }
 125: 
 126:   public String getFormulaExpression()
 127:   {
 128:     return formulaExpression;
 129:   }
 130: 
 131:   public void setFormula(final String formula)
 132:   {
 133:     this.formula = formula;
 134:     if (formula == null)
 135:     {
 136:       formulaNamespace = null;
 137:       formulaExpression = null;
 138:     }
 139:     else
 140:     {
 141:       final int separator = formula.indexOf(':');
 142:       if (separator <= 0 || ((separator + 1) == formula.length()))
 143:       {
 144:         if (formula.startsWith("="))
 145:         {
 146:           formulaNamespace = "report";
 147:           formulaExpression = formula.substring(1);
 148:         }
 149:         else
 150:         {
 151:           // error: invalid formula.
 152:           formulaNamespace = null;
 153:           formulaExpression = null;
 154:         }
 155:       }
 156:       else
 157:       {
 158:         formulaNamespace = formula.substring(0, separator);
 159:         formulaExpression = formula.substring(separator + 1);
 160:       }
 161:     }
 162:     this.compiledFormula = null;
 163:   }
 164: 
 165:   /**
 166:    * When the advance method is called, the function is asked to perform the
 167:    * next step of its computation.
 168:    * <p/>
 169:    * The original function must not be altered during that step (or more
 170:    * correctly, calling advance on the original expression again must not return
 171:    * a different result).
 172:    *
 173:    * @return a copy of the function containing the new state.
 174:    */
 175:   public Function advance() throws DataSourceException
 176:   {
 177:     try
 178:     {
 179:       return (Function) clone();
 180:     }
 181:     catch (CloneNotSupportedException e)
 182:     {
 183:       throw new DataSourceException("Unable to derive a new instance");
 184:     }
 185:   }
 186: 
 187:   private Object computeInitialValue()
 188:   {
 189:     try
 190:     {
 191:       if (initial != null)
 192:       {
 193:         final Formula initFormula = new Formula(initialExpression);
 194:         final ReportFormulaContext context =
 195:             new ReportFormulaContext(getFormulaContext(), getDataRow());
 196:         context.setDeclaringElement(getRuntime().getDeclaringParent());
 197:         try
 198:         {
 199:           initFormula.initialize(context);
 200:           return initFormula.evaluate();
 201:         }
 202:         finally
 203:         {
 204:           context.setDeclaringElement(null);
 205:           context.setDataRow(null);
 206:         }
 207:       }
 208: 
 209:       // if the code above did not trigger, compute a regular thing ..
 210:       return computeRegularValue();
 211:     }
 212:     catch (Exception e)
 213:     {
 214:       Log.debug ("Failed to compute the initial value.");
 215:       return null;
 216:     }
 217:   }
 218: 
 219:   private Object computeRegularValue()
 220:   {
 221:     try
 222:     {
 223:       if (compiledFormula == null)
 224:       {
 225:         compiledFormula = new Formula(formulaExpression);
 226:       }
 227: 
 228:       final ReportFormulaContext context =
 229:           new ReportFormulaContext(getFormulaContext(), getDataRow());
 230:       context.setDeclaringElement(getRuntime().getDeclaringParent());
 231:       try
 232:       {
 233:         compiledFormula.initialize(context);
 234:         return compiledFormula.evaluate();
 235:       }
 236:       finally
 237:       {
 238:         context.setDeclaringElement(null);
 239:         context.setDataRow(null);
 240:       }
 241:     }
 242:     catch (Exception e)
 243:     {
 244:       Log.debug ("Failed to compute the regular value.", e);
 245:       return null;
 246:     }
 247:   }
 248: 
 249:   /**
 250:    * Return the current expression value. <P> The value depends (obviously) on
 251:    * the expression implementation.
 252:    *
 253:    * @return the value of the function.
 254:    */
 255:   public Object computeValue() throws DataSourceException
 256:   {
 257:     try
 258:     {
 259:       if (initialized == false)
 260:       {
 261:         initialized = true;
 262:         return computeInitialValue();
 263:       }
 264:       return computeRegularValue();
 265:     }
 266:     catch (Exception e)
 267:     {
 268:       return null;
 269:     }
 270:   }
 271: 
 272:   /**
 273:    * Clones the expression, expression should be reinitialized after the
 274:    * cloning. <P> Expression maintain no state, cloning is done at the beginning
 275:    * of the report processing to disconnect the used expression from any other
 276:    * object space.
 277:    *
 278:    * @return A clone of this expression.
 279:    * @throws CloneNotSupportedException this should never happen.
 280:    */
 281:   public Object clone() throws CloneNotSupportedException
 282:   {
 283:     final FormulaFunction o = (FormulaFunction) super.clone();
 284:     if (compiledFormula != null)
 285:     {
 286:       o.compiledFormula = (Formula) compiledFormula.clone();
 287:     }
 288:     return o;
 289:   }
 290: 
 291: 
 292:   /**
 293:    * Returns the compiled formula. The formula is not connected to a formula
 294:    * context.
 295:    *
 296:    * @return the formula.
 297:    * @throws org.jfree.formula.parser.ParseException if the formula contains syntax errors.
 298:    */
 299:   public Formula getCompiledFormula()
 300:       throws ParseException
 301:   {
 302:     if (compiledFormula == null)
 303:     {
 304:       compiledFormula = new Formula(formulaExpression);
 305:     }
 306:     return compiledFormula;
 307:   }
 308: }