src/core/net/sf/basedb/util/parser/ColFunction.java

Code
Comments
Other
Rev Date Author Line
2317 24 May 06 nicklas 1 /**
2317 24 May 06 nicklas 2   $Id$
2317 24 May 06 nicklas 3
3675 16 Aug 07 jari 4   Copyright (C) 2006, 2007 Nicklas Nordborg
2317 24 May 06 nicklas 5
2317 24 May 06 nicklas 6   This file is part of BASE - BioArray Software Environment.
2317 24 May 06 nicklas 7   Available at http://base.thep.lu.se/
2317 24 May 06 nicklas 8
2317 24 May 06 nicklas 9   BASE is free software; you can redistribute it and/or
2317 24 May 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
2317 24 May 06 nicklas 12   of the License, or (at your option) any later version.
2317 24 May 06 nicklas 13
2317 24 May 06 nicklas 14   BASE is distributed in the hope that it will be useful,
2317 24 May 06 nicklas 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
2317 24 May 06 nicklas 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2317 24 May 06 nicklas 17   GNU General Public License for more details.
2317 24 May 06 nicklas 18
2317 24 May 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/>.
2317 24 May 06 nicklas 21 */
2317 24 May 06 nicklas 22 package net.sf.basedb.util.parser;
2317 24 May 06 nicklas 23
3023 12 Dec 06 nicklas 24 import java.text.NumberFormat;
3023 12 Dec 06 nicklas 25 import java.text.ParsePosition;
7667 21 Mar 19 nicklas 26 import java.util.Date;
3911 06 Nov 07 nicklas 27 import java.util.LinkedHashMap;
2655 22 Sep 06 nicklas 28 import java.util.List;
2317 24 May 06 nicklas 29 import java.util.Map;
2317 24 May 06 nicklas 30 import java.util.Stack;
3911 06 Nov 07 nicklas 31 import java.util.regex.Pattern;
3911 06 Nov 07 nicklas 32 import java.util.regex.PatternSyntaxException;
2317 24 May 06 nicklas 33
2317 24 May 06 nicklas 34 import org.nfunk.jep.ParseException;
2317 24 May 06 nicklas 35
2317 24 May 06 nicklas 36 import net.sf.basedb.core.BaseException;
7664 20 Mar 19 nicklas 37 import net.sf.basedb.core.Type;
7667 21 Mar 19 nicklas 38 import net.sf.basedb.util.formatter.Formatter;
2317 24 May 06 nicklas 39 import net.sf.basedb.util.jep.JepFunction;
2317 24 May 06 nicklas 40
2317 24 May 06 nicklas 41 /**
2317 24 May 06 nicklas 42   Adds a <code>col()</code> function to Jep. The col function is used with the 
2317 24 May 06 nicklas 43   {@link FlatFileParser} to get the value of a data column. The argument to
2317 24 May 06 nicklas 44   the col function is either the column name or index (0-based). Use the 
2317 24 May 06 nicklas 45   {@link FlatFileParser#getMapper(String)} with an argument starting with an equal
2317 24 May 06 nicklas 46   sign to create a mapper that uses Jep.
2317 24 May 06 nicklas 47   <pre class="code">
2317 24 May 06 nicklas 48 FlatFileParser ffp = ...
3618 01 Aug 07 nicklas 49 Mapper diameterMapper = ffp.getMapper("=col('Radius') * 2");
2317 24 May 06 nicklas 50 while (ffp.hasMoreData())
2317 24 May 06 nicklas 51 {
2317 24 May 06 nicklas 52   Data data = ffp.nextData();
2317 24 May 06 nicklas 53   float diameter = diameterMapper.getFloat(data);
2317 24 May 06 nicklas 54 }
2317 24 May 06 nicklas 55 </pre>
2317 24 May 06 nicklas 56
2317 24 May 06 nicklas 57   @author nicklas
2317 24 May 06 nicklas 58   @version 2.0
2317 24 May 06 nicklas 59   @base.modified $Date$
2317 24 May 06 nicklas 60 */
2317 24 May 06 nicklas 61 public class ColFunction
2317 24 May 06 nicklas 62   implements JepFunction
2317 24 May 06 nicklas 63 {
2317 24 May 06 nicklas 64   
2317 24 May 06 nicklas 65   private final Map<String, Integer> columnHeaders;
3023 12 Dec 06 nicklas 66   private final NumberFormat numberFormat;
7667 21 Mar 19 nicklas 67   private final Formatter<Date> dateFormat;
3023 12 Dec 06 nicklas 68   private final ParsePosition pos;
2317 24 May 06 nicklas 69   private FlatFileParser.Data data;
7664 20 Mar 19 nicklas 70   private Type nextValueType;
4104 28 Jan 08 nicklas 71   private boolean ignoreNonExistingColumns = false;
2317 24 May 06 nicklas 72   
3023 12 Dec 06 nicklas 73   public ColFunction(Map<String, Integer> columnHeaders, NumberFormat numberFormat)
2317 24 May 06 nicklas 74   {
7667 21 Mar 19 nicklas 75     this(columnHeaders, numberFormat, null);
7667 21 Mar 19 nicklas 76   }
7667 21 Mar 19 nicklas 77   
7667 21 Mar 19 nicklas 78   /**
7667 21 Mar 19 nicklas 79     @since 3.15
7667 21 Mar 19 nicklas 80   */
7667 21 Mar 19 nicklas 81   public ColFunction(Map<String, Integer> columnHeaders, NumberFormat numberFormat, Formatter<Date> dateFormat)
7667 21 Mar 19 nicklas 82   {
2317 24 May 06 nicklas 83     this.columnHeaders = columnHeaders;
3023 12 Dec 06 nicklas 84     this.numberFormat = numberFormat;
7667 21 Mar 19 nicklas 85     this.dateFormat = dateFormat;
3023 12 Dec 06 nicklas 86     this.pos = new ParsePosition(0);
2317 24 May 06 nicklas 87   }
7667 21 Mar 19 nicklas 88
3023 12 Dec 06 nicklas 89   public ColFunction(List<String> columnHeaders, NumberFormat numberFormat)
2655 22 Sep 06 nicklas 90   {
7667 21 Mar 19 nicklas 91     this(columnHeaders, numberFormat, null);
7667 21 Mar 19 nicklas 92   }
7667 21 Mar 19 nicklas 93   
7667 21 Mar 19 nicklas 94   /**
7667 21 Mar 19 nicklas 95     @since 3.15
7667 21 Mar 19 nicklas 96   */
7667 21 Mar 19 nicklas 97   public ColFunction(List<String> columnHeaders, NumberFormat numberFormat, Formatter<Date> dateFormat)
7667 21 Mar 19 nicklas 98   {
3023 12 Dec 06 nicklas 99     this.numberFormat = numberFormat;
7667 21 Mar 19 nicklas 100     this.dateFormat = dateFormat;
3023 12 Dec 06 nicklas 101     this.pos = new ParsePosition(0);
3911 06 Nov 07 nicklas 102     this.columnHeaders = new LinkedHashMap<String, Integer>(columnHeaders.size());
2655 22 Sep 06 nicklas 103     int index = 0;
2655 22 Sep 06 nicklas 104     for (String header : columnHeaders)
2655 22 Sep 06 nicklas 105     {
2655 22 Sep 06 nicklas 106       this.columnHeaders.put(header, index);
2655 22 Sep 06 nicklas 107       index++;
2655 22 Sep 06 nicklas 108     }
2655 22 Sep 06 nicklas 109   }
2655 22 Sep 06 nicklas 110   
2317 24 May 06 nicklas 111   /*
2317 24 May 06 nicklas 112     From the JepFunction interface
2317 24 May 06 nicklas 113     -------------------------------------------
2317 24 May 06 nicklas 114   */
2317 24 May 06 nicklas 115   /**
2317 24 May 06 nicklas 116     @return The string "col"
2317 24 May 06 nicklas 117   */
6127 14 Sep 12 nicklas 118   @Override
2317 24 May 06 nicklas 119   public String getFunctionName()
2317 24 May 06 nicklas 120   {
2317 24 May 06 nicklas 121     return "col";
2317 24 May 06 nicklas 122   }
2317 24 May 06 nicklas 123   // -------------------------------------------
2317 24 May 06 nicklas 124   /*
2317 24 May 06 nicklas 125     From the PostfixMathCommandI interface
2317 24 May 06 nicklas 126     -------------------------------------------
2317 24 May 06 nicklas 127   */
2317 24 May 06 nicklas 128   /**
2317 24 May 06 nicklas 129     @return Always 1
2317 24 May 06 nicklas 130   */
6127 14 Sep 12 nicklas 131   @Override
2317 24 May 06 nicklas 132   public int getNumberOfParameters()
2317 24 May 06 nicklas 133   {
2317 24 May 06 nicklas 134     return 1;
2317 24 May 06 nicklas 135   }
6127 14 Sep 12 nicklas 136   @Override
2317 24 May 06 nicklas 137   public void setCurNumberOfParameters(int n)
2317 24 May 06 nicklas 138   {}
6127 14 Sep 12 nicklas 139   @Override
2474 31 Jul 06 nicklas 140   public boolean checkNumberOfParameters(int n)
2474 31 Jul 06 nicklas 141   {
2474 31 Jul 06 nicklas 142     return n == 1;
2474 31 Jul 06 nicklas 143   }
6127 14 Sep 12 nicklas 144   @Override
6875 20 Apr 15 nicklas 145   @SuppressWarnings({"unchecked", "rawtypes"})
2317 24 May 06 nicklas 146   public void run(Stack stack)
2317 24 May 06 nicklas 147     throws ParseException
2317 24 May 06 nicklas 148   {
2317 24 May 06 nicklas 149     if (stack == null || stack.empty()) 
2317 24 May 06 nicklas 150     {
2317 24 May 06 nicklas 151       throw new ParseException("Stack is empty");
2317 24 May 06 nicklas 152     }
2317 24 May 06 nicklas 153     Object argument = stack.pop();
7664 20 Mar 19 nicklas 154     Integer column = null;
2317 24 May 06 nicklas 155     if (argument instanceof Number)
2317 24 May 06 nicklas 156     {
7664 20 Mar 19 nicklas 157       column = ((Number)argument).intValue();
2317 24 May 06 nicklas 158     }
2317 24 May 06 nicklas 159     else if (argument instanceof String)
2317 24 May 06 nicklas 160     {
2317 24 May 06 nicklas 161       String colName = (String)argument;
7664 20 Mar 19 nicklas 162       column = columnHeaders.get(colName);
3911 06 Nov 07 nicklas 163       if (column == null) column = findColumn(colName);
3911 06 Nov 07 nicklas 164       if (column == null)
2317 24 May 06 nicklas 165       {
4104 28 Jan 08 nicklas 166         if (!ignoreNonExistingColumns)
4104 28 Jan 08 nicklas 167         {
4104 28 Jan 08 nicklas 168           throw new BaseException("Column '" + colName + "' not found in column headers.");
4104 28 Jan 08 nicklas 169         }
2317 24 May 06 nicklas 170       }
2317 24 May 06 nicklas 171     }
2317 24 May 06 nicklas 172     else
2317 24 May 06 nicklas 173     {
2317 24 May 06 nicklas 174       throw new ParseException("Invalid parameter type: " + argument + "; expected number");
2317 24 May 06 nicklas 175     }
7664 20 Mar 19 nicklas 176     
7664 20 Mar 19 nicklas 177     Object value = null;
7665 20 Mar 19 nicklas 178     if (column != null && column < data.columns())
2317 24 May 06 nicklas 179     {
7672 21 Mar 19 nicklas 180       try
3023 12 Dec 06 nicklas 181       {
7672 21 Mar 19 nicklas 182         value = data.getDouble(column, numberFormat, false);
3023 12 Dec 06 nicklas 183       }
7672 21 Mar 19 nicklas 184       catch (RuntimeException ex)
7667 21 Mar 19 nicklas 185       {
7672 21 Mar 19 nicklas 186         if (nextValueType.isTemporal())
7672 21 Mar 19 nicklas 187         {
7672 21 Mar 19 nicklas 188           value = data.getDate(column, dateFormat, true);
7672 21 Mar 19 nicklas 189         }
7672 21 Mar 19 nicklas 190         else
7672 21 Mar 19 nicklas 191         {
7672 21 Mar 19 nicklas 192           value = data.getString(column);
7672 21 Mar 19 nicklas 193         }
7667 21 Mar 19 nicklas 194       }
2317 24 May 06 nicklas 195     }
7664 20 Mar 19 nicklas 196     stack.push(value);
2317 24 May 06 nicklas 197   }
2317 24 May 06 nicklas 198   // -------------------------------------------
2317 24 May 06 nicklas 199
4104 28 Jan 08 nicklas 200   /**
4104 28 Jan 08 nicklas 201     Set to TRUE to ignore non-existing columns. Set to FALSE to
4104 28 Jan 08 nicklas 202     throw an exception (default).
4104 28 Jan 08 nicklas 203     @since 2.6
4104 28 Jan 08 nicklas 204   */
4104 28 Jan 08 nicklas 205   public void setIgnoreNonExistingColumns(boolean ignoreNonExistingColumns)
4104 28 Jan 08 nicklas 206   {
4104 28 Jan 08 nicklas 207     this.ignoreNonExistingColumns = ignoreNonExistingColumns;
4104 28 Jan 08 nicklas 208   }
4104 28 Jan 08 nicklas 209   
7664 20 Mar 19 nicklas 210   public void setData(FlatFileParser.Data data, Type valueType)
2317 24 May 06 nicklas 211   {
2317 24 May 06 nicklas 212     this.data = data;
7664 20 Mar 19 nicklas 213     this.nextValueType = valueType;
2317 24 May 06 nicklas 214   }
3911 06 Nov 07 nicklas 215   
3911 06 Nov 07 nicklas 216   /**
3911 06 Nov 07 nicklas 217     Find column index by checking each column header against a
3911 06 Nov 07 nicklas 218     regular expression. The first match found is returned. The
6898 12 May 15 nicklas 219     map is updated with a new regex -&gt; index entry.
3911 06 Nov 07 nicklas 220     @return The column index or null if no column is found or if the 
3911 06 Nov 07 nicklas 221       string is not a valid regular expression
3911 06 Nov 07 nicklas 222   */
3911 06 Nov 07 nicklas 223   private Integer findColumn(String regex)
3911 06 Nov 07 nicklas 224   {
3911 06 Nov 07 nicklas 225     try
3911 06 Nov 07 nicklas 226     {
3911 06 Nov 07 nicklas 227       Pattern p = Pattern.compile(regex);
3911 06 Nov 07 nicklas 228       Integer index = null;
3911 06 Nov 07 nicklas 229       for (Map.Entry<String, Integer> entry : columnHeaders.entrySet())
3911 06 Nov 07 nicklas 230       {
3911 06 Nov 07 nicklas 231         String column = entry.getKey();
3911 06 Nov 07 nicklas 232         if (p.matcher(column).matches())
3911 06 Nov 07 nicklas 233         {
3911 06 Nov 07 nicklas 234           index = entry.getValue();
3911 06 Nov 07 nicklas 235           break;
3911 06 Nov 07 nicklas 236         }
3911 06 Nov 07 nicklas 237       }
3911 06 Nov 07 nicklas 238       if (index != null) columnHeaders.put(regex, index);
3911 06 Nov 07 nicklas 239       return index;
3911 06 Nov 07 nicklas 240     }
3911 06 Nov 07 nicklas 241     catch (PatternSyntaxException ex)
3911 06 Nov 07 nicklas 242     {
3911 06 Nov 07 nicklas 243       return null;
3911 06 Nov 07 nicklas 244     }
3911 06 Nov 07 nicklas 245   }
2317 24 May 06 nicklas 246
2317 24 May 06 nicklas 247 }