src/core/net/sf/basedb/util/jep/MeanFunction.java

Code
Comments
Other
Rev Date Author Line
1915 06 Feb 06 nicklas 1 /*
1915 06 Feb 06 nicklas 2   $Id$
1915 06 Feb 06 nicklas 3
4889 06 Apr 09 nicklas 4   Copyright (C) 2006 Jari Häkkinen, Nicklas Nordborg, Gregory Vincic
1915 06 Feb 06 nicklas 5
2304 22 May 06 jari 6   This file is part of BASE - BioArray Software Environment.
2304 22 May 06 jari 7   Available at http://base.thep.lu.se/
1915 06 Feb 06 nicklas 8
1915 06 Feb 06 nicklas 9   BASE is free software; you can redistribute it and/or
1915 06 Feb 06 nicklas 10   modify it under the terms of the GNU General Public License
4479 05 Sep 08 jari 11   as published by the Free Software Foundation; either version 3
1915 06 Feb 06 nicklas 12   of the License, or (at your option) any later version.
1915 06 Feb 06 nicklas 13
1915 06 Feb 06 nicklas 14   BASE is distributed in the hope that it will be useful,
1915 06 Feb 06 nicklas 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
1915 06 Feb 06 nicklas 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1915 06 Feb 06 nicklas 17   GNU General Public License for more details.
1915 06 Feb 06 nicklas 18
1915 06 Feb 06 nicklas 19   You should have received a copy of the GNU General Public License
4515 11 Sep 08 jari 20   along with BASE. If not, see <http://www.gnu.org/licenses/>.
1915 06 Feb 06 nicklas 21 */
1915 06 Feb 06 nicklas 22 package net.sf.basedb.util.jep;
1915 06 Feb 06 nicklas 23
1915 06 Feb 06 nicklas 24 import net.sf.basedb.core.DbControl;
1915 06 Feb 06 nicklas 25 import net.sf.basedb.core.RawBioAssay;
1915 06 Feb 06 nicklas 26 import net.sf.basedb.core.DynamicResultIterator;
1915 06 Feb 06 nicklas 27 import net.sf.basedb.core.DynamicRawDataQuery;
1915 06 Feb 06 nicklas 28 import net.sf.basedb.core.RawDataUtil;
1915 06 Feb 06 nicklas 29 import net.sf.basedb.core.BaseException;
1915 06 Feb 06 nicklas 30 import net.sf.basedb.core.data.RawData;
1915 06 Feb 06 nicklas 31 import net.sf.basedb.core.query.Aggregations;
1915 06 Feb 06 nicklas 32 import net.sf.basedb.core.query.Dynamic;
2726 12 Oct 06 nicklas 33 import net.sf.basedb.core.query.Expression;
1915 06 Feb 06 nicklas 34 import net.sf.basedb.core.query.Selects;
1915 06 Feb 06 nicklas 35
1915 06 Feb 06 nicklas 36 import java.util.Stack;
1915 06 Feb 06 nicklas 37 import java.util.Map;
1915 06 Feb 06 nicklas 38 import java.util.HashMap;
1915 06 Feb 06 nicklas 39 import java.sql.SQLException;
2726 12 Oct 06 nicklas 40
2726 12 Oct 06 nicklas 41 import org.nfunk.jep.Node;
1915 06 Feb 06 nicklas 42 import org.nfunk.jep.ParseException;
1915 06 Feb 06 nicklas 43
1915 06 Feb 06 nicklas 44
1915 06 Feb 06 nicklas 45 /**
1915 06 Feb 06 nicklas 46   A JEP function class that adds a <code>mean(string)</code> function to a 
1915 06 Feb 06 nicklas 47   JEP expression parser. The function will calculate the mean value of the raw data 
1915 06 Feb 06 nicklas 48   property with the given name. For example: 
1915 06 Feb 06 nicklas 49   <code>mean('ch1BgMean')</code>
1915 06 Feb 06 nicklas 50   <p>
1915 06 Feb 06 nicklas 51   To be able to use this function it must be registered with the JEP
1915 06 Feb 06 nicklas 52   parser and, before the expression is evaluated, a rawbioassay object must be set.
1915 06 Feb 06 nicklas 53   For example we can evaluate an expression for every raw data object
1915 06 Feb 06 nicklas 54   in a raw bioassay:
1915 06 Feb 06 nicklas 55   
1915 06 Feb 06 nicklas 56   <pre class="code">
1915 06 Feb 06 nicklas 57 DbControl dc = ...
1915 06 Feb 06 nicklas 58 RawBioAssay assay = ...
1915 06 Feb 06 nicklas 59 String expression = "raw('ch1FgMean') - mean('ch1BgMean')";
1915 06 Feb 06 nicklas 60 RawFunction raw = new RawFunction(assay.getRawDataType());
1915 06 Feb 06 nicklas 61 MeanFunction mean = new MeanFunction(assay);
1915 06 Feb 06 nicklas 62 JEP jep = JepUtil.newJep(expression, raw, mean);
1915 06 Feb 06 nicklas 63 DataResultIterator&lt;RawData&gt; result = 
1915 06 Feb 06 nicklas 64    assay.getRawData().iterate(dc);
1915 06 Feb 06 nicklas 65 while (result.hasNext())
1915 06 Feb 06 nicklas 66 {
1915 06 Feb 06 nicklas 67    raw.setRawData(result.next());
1915 06 Feb 06 nicklas 68    double value = jep.getValue();
1915 06 Feb 06 nicklas 69    // Do something with the value
1915 06 Feb 06 nicklas 70 }
1915 06 Feb 06 nicklas 71 result.close();
1915 06 Feb 06 nicklas 72 </pre>
1915 06 Feb 06 nicklas 73
1915 06 Feb 06 nicklas 74   @author Nicklas
1915 06 Feb 06 nicklas 75   @version 2.0
1915 06 Feb 06 nicklas 76   @base.modified $Date$
1915 06 Feb 06 nicklas 77   @see Jep
1915 06 Feb 06 nicklas 78 */
1915 06 Feb 06 nicklas 79 public class MeanFunction
2726 12 Oct 06 nicklas 80   implements JepExpressionFunction
1915 06 Feb 06 nicklas 81 {
1915 06 Feb 06 nicklas 82   /**
1915 06 Feb 06 nicklas 83     Holds a cache of the values.
1915 06 Feb 06 nicklas 84   */
1915 06 Feb 06 nicklas 85   private final Map<String, Float> means;
1915 06 Feb 06 nicklas 86   private final DbControl dc;
1915 06 Feb 06 nicklas 87   private int numParameters;
1915 06 Feb 06 nicklas 88   private RawBioAssay rawBioAssay;
1915 06 Feb 06 nicklas 89   private RawData rawData;
1915 06 Feb 06 nicklas 90
1915 06 Feb 06 nicklas 91   /**
1915 06 Feb 06 nicklas 92     Create a new instance of this function working with raw data of
1915 06 Feb 06 nicklas 93     the specified raw bio assay.
1958 09 Feb 06 gregory 94     @param dc DbControl used in this function
1915 06 Feb 06 nicklas 95   */
1915 06 Feb 06 nicklas 96   public MeanFunction(DbControl dc)
1915 06 Feb 06 nicklas 97   {
1915 06 Feb 06 nicklas 98     this.dc = dc;
1915 06 Feb 06 nicklas 99     this.means = new HashMap<String, Float>();
1915 06 Feb 06 nicklas 100   }
1915 06 Feb 06 nicklas 101   
1915 06 Feb 06 nicklas 102   /*
1915 06 Feb 06 nicklas 103     From the JepFunction interface
1915 06 Feb 06 nicklas 104     -------------------------------------------
1915 06 Feb 06 nicklas 105   */
1915 06 Feb 06 nicklas 106   /**
1915 06 Feb 06 nicklas 107     @return The string "mean"
1915 06 Feb 06 nicklas 108   */
6127 14 Sep 12 nicklas 109   @Override
1915 06 Feb 06 nicklas 110   public String getFunctionName()
1915 06 Feb 06 nicklas 111   {
1915 06 Feb 06 nicklas 112     return "mean";
1915 06 Feb 06 nicklas 113   }
1915 06 Feb 06 nicklas 114   // -------------------------------------------
1915 06 Feb 06 nicklas 115   /*
2726 12 Oct 06 nicklas 116     From the JepExpressionFunction interface
2726 12 Oct 06 nicklas 117     -------------------------------------------
2726 12 Oct 06 nicklas 118   */
2726 12 Oct 06 nicklas 119   /**
2981 30 Nov 06 nicklas 120     Use the {@link Dynamic#meanRawData(String)} method to create an
2726 12 Oct 06 nicklas 121     expression for the mean of the given raw data property.
2726 12 Oct 06 nicklas 122   */
6127 14 Sep 12 nicklas 123   @Override
2726 12 Oct 06 nicklas 124   public Expression toExpression(Node node)
2726 12 Oct 06 nicklas 125   {
2726 12 Oct 06 nicklas 126     int numChildren = node.jjtGetNumChildren();
2726 12 Oct 06 nicklas 127     if (numChildren != 1)
2726 12 Oct 06 nicklas 128     {
2726 12 Oct 06 nicklas 129       throw new BaseException("Invalid number of arguments for 'mean' function: " + numChildren);
2726 12 Oct 06 nicklas 130     }
2726 12 Oct 06 nicklas 131     return Dynamic.meanRawData(Jep.nodeToString(node.jjtGetChild(0)));
2726 12 Oct 06 nicklas 132   }
2726 12 Oct 06 nicklas 133   // -------------------------------------------
2726 12 Oct 06 nicklas 134   /*
1915 06 Feb 06 nicklas 135     From the PostfixMathCommandI interface
1915 06 Feb 06 nicklas 136     -------------------------------------------
1915 06 Feb 06 nicklas 137   */
1915 06 Feb 06 nicklas 138   /**
1915 06 Feb 06 nicklas 139     @return Always 1
1915 06 Feb 06 nicklas 140   */
6127 14 Sep 12 nicklas 141   @Override
1915 06 Feb 06 nicklas 142   public int getNumberOfParameters()
1915 06 Feb 06 nicklas 143   {
1915 06 Feb 06 nicklas 144     return 1;
1915 06 Feb 06 nicklas 145   }
6127 14 Sep 12 nicklas 146   @Override
1915 06 Feb 06 nicklas 147   public void setCurNumberOfParameters(int n)
1915 06 Feb 06 nicklas 148   {
1915 06 Feb 06 nicklas 149     this.numParameters = n;
1915 06 Feb 06 nicklas 150   }
6127 14 Sep 12 nicklas 151   @Override
2474 31 Jul 06 nicklas 152   public boolean checkNumberOfParameters(int n)
2474 31 Jul 06 nicklas 153   {
2474 31 Jul 06 nicklas 154     return n == 1;
2474 31 Jul 06 nicklas 155   }
6127 14 Sep 12 nicklas 156   @Override
6875 20 Apr 15 nicklas 157   @SuppressWarnings({"unchecked", "rawtypes"})
1915 06 Feb 06 nicklas 158   public void run(Stack stack)
1915 06 Feb 06 nicklas 159     throws ParseException
1915 06 Feb 06 nicklas 160   {
1915 06 Feb 06 nicklas 161     if (stack == null || stack.empty()) 
1915 06 Feb 06 nicklas 162     {
1915 06 Feb 06 nicklas 163       throw new ParseException("Stack is empty");
1915 06 Feb 06 nicklas 164     }
1915 06 Feb 06 nicklas 165     Object propertyName = stack.pop();
1915 06 Feb 06 nicklas 166     if (propertyName instanceof String)
1915 06 Feb 06 nicklas 167     {
1915 06 Feb 06 nicklas 168       stack.push(mean((String)propertyName));
1915 06 Feb 06 nicklas 169     }
1915 06 Feb 06 nicklas 170     else
1915 06 Feb 06 nicklas 171     {
1915 06 Feb 06 nicklas 172       throw new ParseException("Invalid parameter type: " + propertyName + "; expected string");
1915 06 Feb 06 nicklas 173     }
1915 06 Feb 06 nicklas 174   }
1915 06 Feb 06 nicklas 175   // -------------------------------------------
1915 06 Feb 06 nicklas 176
1915 06 Feb 06 nicklas 177   /**
1915 06 Feb 06 nicklas 178     Set a new raw data object that will be used the next time the
1915 06 Feb 06 nicklas 179     JEP expression is evaluated.
1915 06 Feb 06 nicklas 180     @param rawData The raw data object to use
1915 06 Feb 06 nicklas 181   */
1915 06 Feb 06 nicklas 182   public void setRawData(RawData rawData)
1915 06 Feb 06 nicklas 183   {
1915 06 Feb 06 nicklas 184     this.rawData = rawData;
1915 06 Feb 06 nicklas 185   }
1915 06 Feb 06 nicklas 186   /**
1915 06 Feb 06 nicklas 187     Get the current raw data object used when evaluating the JEP expression.
1915 06 Feb 06 nicklas 188   */
1915 06 Feb 06 nicklas 189   public RawData getRawData()
1915 06 Feb 06 nicklas 190   {
1915 06 Feb 06 nicklas 191     return rawData;
1915 06 Feb 06 nicklas 192   }
1915 06 Feb 06 nicklas 193
1915 06 Feb 06 nicklas 194   
1915 06 Feb 06 nicklas 195   /**
1915 06 Feb 06 nicklas 196     Get the value of the specified property of the current raw data object.
1915 06 Feb 06 nicklas 197     This method uses Hibernate metadata to find the value.
4020 29 Nov 07 martin 198     @param propertyName The name of the raw data property. Null is not allowed.
4020 29 Nov 07 martin 199      @return The mean value as a float. 
4020 29 Nov 07 martin 200       @throws ParseException If the property name is null or 
4020 29 Nov 07 martin 201          if there is another error.
1915 06 Feb 06 nicklas 202   */
2726 12 Oct 06 nicklas 203   public float mean(String propertyName)
1915 06 Feb 06 nicklas 204     throws ParseException
1915 06 Feb 06 nicklas 205   {
1915 06 Feb 06 nicklas 206     if (propertyName == null)
1915 06 Feb 06 nicklas 207     {
1915 06 Feb 06 nicklas 208       throw new ParseException("No property name has been specified for function mean()");
1915 06 Feb 06 nicklas 209     }
1915 06 Feb 06 nicklas 210     if (rawData == null)
1915 06 Feb 06 nicklas 211     {
1915 06 Feb 06 nicklas 212       throw new ParseException("No raw data object has been specified for function mean('"+propertyName+"')");
1915 06 Feb 06 nicklas 213     }
1915 06 Feb 06 nicklas 214     Float theMean = null;
1915 06 Feb 06 nicklas 215     try
1915 06 Feb 06 nicklas 216     {
1915 06 Feb 06 nicklas 217       RawBioAssay rba = RawDataUtil.getRawBioAssay(dc, rawData);
1915 06 Feb 06 nicklas 218       if (rawBioAssay == null || rba.getId() != rawBioAssay.getId())
1915 06 Feb 06 nicklas 219       {
1915 06 Feb 06 nicklas 220         // Raw data from is from a different RawBioAssay. Clean cache.
1915 06 Feb 06 nicklas 221         rawBioAssay = rba;
1915 06 Feb 06 nicklas 222         means.clear();
1915 06 Feb 06 nicklas 223       }
1915 06 Feb 06 nicklas 224       theMean = means.get(propertyName);
1915 06 Feb 06 nicklas 225       if (theMean == null)
1915 06 Feb 06 nicklas 226       {
1915 06 Feb 06 nicklas 227         // Value not found in cache, query the database
1915 06 Feb 06 nicklas 228         DynamicRawDataQuery rawQuery = rawBioAssay.getDynamicRawData();
1915 06 Feb 06 nicklas 229         rawQuery.select(Selects.expression(Aggregations.mean(Dynamic.rawData(propertyName)), "mean"));
1915 06 Feb 06 nicklas 230         DynamicResultIterator result = rawQuery.iterate(rawBioAssay.getDbControl());
1915 06 Feb 06 nicklas 231         theMean = result.next().getFloat(1);
1915 06 Feb 06 nicklas 232         means.put(propertyName, theMean);
1915 06 Feb 06 nicklas 233       }
1915 06 Feb 06 nicklas 234     }
1915 06 Feb 06 nicklas 235     catch (SQLException ex)
1915 06 Feb 06 nicklas 236     {
1915 06 Feb 06 nicklas 237       throw new ParseException(ex.getMessage());
1915 06 Feb 06 nicklas 238     }
1915 06 Feb 06 nicklas 239     catch (BaseException ex)
1915 06 Feb 06 nicklas 240     {
1915 06 Feb 06 nicklas 241       throw new ParseException(ex.getMessage());
1915 06 Feb 06 nicklas 242     }
1915 06 Feb 06 nicklas 243     return theMean;
1915 06 Feb 06 nicklas 244   }
1915 06 Feb 06 nicklas 245 }