src/core/net/sf/basedb/util/importer/spotdata/SynchronizedSpotDataParser.java

Code
Comments
Other
Rev Date Author Line
5227 01 Feb 10 nicklas 1 /**
5227 01 Feb 10 nicklas 2   $Id$
5227 01 Feb 10 nicklas 3
5227 01 Feb 10 nicklas 4   Copyright (C) 2010 Nicklas Nordborg
5227 01 Feb 10 nicklas 5
5227 01 Feb 10 nicklas 6   This file is part of BASE - BioArray Software Environment.
5227 01 Feb 10 nicklas 7   Available at http://base.thep.lu.se/
5227 01 Feb 10 nicklas 8
5227 01 Feb 10 nicklas 9   BASE is free software; you can redistribute it and/or
5227 01 Feb 10 nicklas 10   modify it under the terms of the GNU General Public License
5227 01 Feb 10 nicklas 11   as published by the Free Software Foundation; either version 3
5227 01 Feb 10 nicklas 12   of the License, or (at your option) any later version.
5227 01 Feb 10 nicklas 13
5227 01 Feb 10 nicklas 14   BASE is distributed in the hope that it will be useful,
5227 01 Feb 10 nicklas 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
5227 01 Feb 10 nicklas 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5227 01 Feb 10 nicklas 17   GNU General Public License for more details.
5227 01 Feb 10 nicklas 18
5227 01 Feb 10 nicklas 19   You should have received a copy of the GNU General Public License
5227 01 Feb 10 nicklas 20   along with BASE. If not, see <http://www.gnu.org/licenses/>.
5227 01 Feb 10 nicklas 21 */
5227 01 Feb 10 nicklas 22 package net.sf.basedb.util.importer.spotdata;
5227 01 Feb 10 nicklas 23
5227 01 Feb 10 nicklas 24 import java.io.IOException;
5227 01 Feb 10 nicklas 25 import java.util.ArrayList;
5227 01 Feb 10 nicklas 26 import java.util.List;
5227 01 Feb 10 nicklas 27
5227 01 Feb 10 nicklas 28 import net.sf.basedb.core.signal.ThreadSignalHandler;
5227 01 Feb 10 nicklas 29 import net.sf.basedb.util.bfs.AnnotationParser;
5227 01 Feb 10 nicklas 30 import net.sf.basedb.util.bfs.BfsParser;
5227 01 Feb 10 nicklas 31 import net.sf.basedb.util.bfs.DataParser;
5227 01 Feb 10 nicklas 32 import net.sf.basedb.util.bfs.EventHandler;
5227 01 Feb 10 nicklas 33 import net.sf.basedb.util.bfs.EventType;
5227 01 Feb 10 nicklas 34
5227 01 Feb 10 nicklas 35 /**
5227 01 Feb 10 nicklas 36   A parser that synchronizes the parsing of multiple underlying
5227 01 Feb 10 nicklas 37   data parsers and a master reporter annotations parser. Before
5227 01 Feb 10 nicklas 38   it can be used a master parser must be set by {@link #setMasterParser(AnnotationParser)}.
5227 01 Feb 10 nicklas 39   Then, one or more data parsers is needed {@link #addDataParser(DataParser)}. 
5227 01 Feb 10 nicklas 40   All parsers must have been parsed to beginning-of-file 
5227 01 Feb 10 nicklas 41   (eg. {@link AnnotationParser#parseToBof()} and {@link DataParser#parseToBof()}) before
5227 01 Feb 10 nicklas 42   they are added to this class. The {@link #parse(EventHandler)} method will then
5227 01 Feb 10 nicklas 43   call {@link AnnotationParser#nextData()} and {@link DataParser#nextData()}
5227 01 Feb 10 nicklas 44   for each parser as long as data is returned. All parsers must resturn at least
5227 01 Feb 10 nicklas 45   as many data lines as the master parser or an exception is thrown. 
5227 01 Feb 10 nicklas 46
5227 01 Feb 10 nicklas 47   @author Nicklas
5227 01 Feb 10 nicklas 48   @version 2.15
5227 01 Feb 10 nicklas 49   @base.modified $Date$
5227 01 Feb 10 nicklas 50 */
5227 01 Feb 10 nicklas 51 public class SynchronizedSpotDataParser
5227 01 Feb 10 nicklas 52   implements BfsParser
5227 01 Feb 10 nicklas 53 {
5227 01 Feb 10 nicklas 54
5227 01 Feb 10 nicklas 55   /**
5227 01 Feb 10 nicklas 56     Event type that is issued for each data line. The event data is an
5227 01 Feb 10 nicklas 57     array with {@link SynchronizedData} objects. The first entry in the
5227 01 Feb 10 nicklas 58     array contains information from the master parser, the following
5227 01 Feb 10 nicklas 59     entries contain information for the data parsers in the order
5227 01 Feb 10 nicklas 60     they were added.
5227 01 Feb 10 nicklas 61   */
5227 01 Feb 10 nicklas 62   public static final EventType<SynchronizedData[]> DATA_EVENT = 
5227 01 Feb 10 nicklas 63     new EventType<SynchronizedData[]>("synchonized.data");
5227 01 Feb 10 nicklas 64
5227 01 Feb 10 nicklas 65   
5227 01 Feb 10 nicklas 66   private AnnotationParser masterParser;
5227 01 Feb 10 nicklas 67   private List<DataParser> dataParsers;
5227 01 Feb 10 nicklas 68   
5227 01 Feb 10 nicklas 69   /**
5227 01 Feb 10 nicklas 70     Create a new synchronized data parser.
5227 01 Feb 10 nicklas 71   */
5227 01 Feb 10 nicklas 72   public SynchronizedSpotDataParser()
5227 01 Feb 10 nicklas 73   {
5227 01 Feb 10 nicklas 74     this.dataParsers = new ArrayList<DataParser>();
5227 01 Feb 10 nicklas 75   }
5227 01 Feb 10 nicklas 76   
5227 01 Feb 10 nicklas 77   /**
5227 01 Feb 10 nicklas 78     Sets the master parser. This parser should normally parse a
5227 01 Feb 10 nicklas 79     reporter annotations file.
5227 01 Feb 10 nicklas 80   */
5227 01 Feb 10 nicklas 81   public void setMasterParser(AnnotationParser parser)
5227 01 Feb 10 nicklas 82   {
5227 01 Feb 10 nicklas 83     this.masterParser = parser;
5227 01 Feb 10 nicklas 84   }
5227 01 Feb 10 nicklas 85   
5227 01 Feb 10 nicklas 86   /**
5227 01 Feb 10 nicklas 87     Adds a data parser. The parser should parse a data file
5227 01 Feb 10 nicklas 88     that has the same number of data lines as the master parser.
5227 01 Feb 10 nicklas 89     Each line contains data identified by the corresponding 
5227 01 Feb 10 nicklas 90     reporter in the master parser file.
5227 01 Feb 10 nicklas 91   */
5227 01 Feb 10 nicklas 92   public void addDataParser(DataParser parser)
5227 01 Feb 10 nicklas 93   {
5227 01 Feb 10 nicklas 94     this.dataParsers.add(parser);
5227 01 Feb 10 nicklas 95   }
5227 01 Feb 10 nicklas 96   
5227 01 Feb 10 nicklas 97   /**
5227 01 Feb 10 nicklas 98     @return Always null, since we are parsing multiple files
5227 01 Feb 10 nicklas 99   */
5227 01 Feb 10 nicklas 100   @Override
5227 01 Feb 10 nicklas 101   public String getFilename()
5227 01 Feb 10 nicklas 102   {
5227 01 Feb 10 nicklas 103     return null;
5227 01 Feb 10 nicklas 104   }
5227 01 Feb 10 nicklas 105
5227 01 Feb 10 nicklas 106   /**
5227 01 Feb 10 nicklas 107     @return The file size of the master parser
5227 01 Feb 10 nicklas 108   */
5227 01 Feb 10 nicklas 109   @Override
5227 01 Feb 10 nicklas 110   public long getFileSize()
5227 01 Feb 10 nicklas 111   {
5227 01 Feb 10 nicklas 112     return masterParser.getFileSize();
5227 01 Feb 10 nicklas 113   }
5227 01 Feb 10 nicklas 114   
5227 01 Feb 10 nicklas 115   /**
5227 01 Feb 10 nicklas 116     @return The current line number in the file parsed by the 
5227 01 Feb 10 nicklas 117       master parser
5227 01 Feb 10 nicklas 118   */
5227 01 Feb 10 nicklas 119   @Override
5227 01 Feb 10 nicklas 120   public int getCurrentLine()
5227 01 Feb 10 nicklas 121   {
5227 01 Feb 10 nicklas 122     return masterParser.getCurrentLine();
5227 01 Feb 10 nicklas 123   }
5227 01 Feb 10 nicklas 124   
5227 01 Feb 10 nicklas 125   /**
5227 01 Feb 10 nicklas 126     @return The number of bytes parsed by the master parser
5227 01 Feb 10 nicklas 127   */
5227 01 Feb 10 nicklas 128   @Override
5227 01 Feb 10 nicklas 129   public long getParsedBytes()
5227 01 Feb 10 nicklas 130   {
5227 01 Feb 10 nicklas 131     return masterParser.getParsedBytes();
5227 01 Feb 10 nicklas 132   }
5227 01 Feb 10 nicklas 133   
5319 20 Apr 10 nicklas 134   @Override
5319 20 Apr 10 nicklas 135   public void close() 
5319 20 Apr 10 nicklas 136   {
5319 20 Apr 10 nicklas 137     if (masterParser != null) masterParser.close();
5319 20 Apr 10 nicklas 138     for (DataParser parser : dataParsers)
5319 20 Apr 10 nicklas 139     {
5319 20 Apr 10 nicklas 140       parser.close();
5319 20 Apr 10 nicklas 141     }
5319 20 Apr 10 nicklas 142   }
5319 20 Apr 10 nicklas 143
5227 01 Feb 10 nicklas 144   /**
5227 01 Feb 10 nicklas 145     Begin parsing and issue events to the given event handler. For each
5227 01 Feb 10 nicklas 146     data line a {@link #DATA_EVENT} is sent to the event handler. When 
5227 01 Feb 10 nicklas 147     the end-of-file has been a {@link DataParser#END_OF_FILE_EVENT} is
5227 01 Feb 10 nicklas 148     sent.
5227 01 Feb 10 nicklas 149     
5227 01 Feb 10 nicklas 150     @param handler An event handler
5227 01 Feb 10 nicklas 151     @throws IOException If there is an error reading the stream data
5227 01 Feb 10 nicklas 152     @throws NullPointerException If the event handler or master parser is null
5227 01 Feb 10 nicklas 153   */
5227 01 Feb 10 nicklas 154   public void parse(EventHandler handler)
5227 01 Feb 10 nicklas 155     throws IOException
5227 01 Feb 10 nicklas 156   {
5227 01 Feb 10 nicklas 157     if (handler == null) throw new NullPointerException("handler");
5227 01 Feb 10 nicklas 158     if (masterParser == null) throw new NullPointerException("masterParser");
5227 01 Feb 10 nicklas 159     
5227 01 Feb 10 nicklas 160     SynchronizedData[] data = new SynchronizedData[1+dataParsers.size()];
5227 01 Feb 10 nicklas 161     data[0] = new SynchronizedData(masterParser);
5227 01 Feb 10 nicklas 162     int i = 1;
5227 01 Feb 10 nicklas 163     for (DataParser parser : dataParsers)
5227 01 Feb 10 nicklas 164     {
5227 01 Feb 10 nicklas 165       data[i] = new SynchronizedData(parser);
5227 01 Feb 10 nicklas 166       ++i;
5227 01 Feb 10 nicklas 167     }
5227 01 Feb 10 nicklas 168     
5227 01 Feb 10 nicklas 169     String[] tmp = masterParser.nextData();
5227 01 Feb 10 nicklas 170     while (tmp != null)
5227 01 Feb 10 nicklas 171     {
5227 01 Feb 10 nicklas 172       ThreadSignalHandler.checkInterrupted();
5227 01 Feb 10 nicklas 173       data[0].setData(tmp);
5227 01 Feb 10 nicklas 174       i = 1;
5227 01 Feb 10 nicklas 175       for (DataParser parser : dataParsers)
5227 01 Feb 10 nicklas 176       {
5227 01 Feb 10 nicklas 177         tmp = parser.nextData();
5227 01 Feb 10 nicklas 178         if (tmp == null)
5227 01 Feb 10 nicklas 179         {
5227 01 Feb 10 nicklas 180           throw new IOException("Unexpected end of file at line " + 
5227 01 Feb 10 nicklas 181             parser.getCurrentLine() + " in file " + parser.getFilename());
5227 01 Feb 10 nicklas 182         }
5227 01 Feb 10 nicklas 183         data[i].setData(tmp);
5227 01 Feb 10 nicklas 184         ++i;
5227 01 Feb 10 nicklas 185       }
5227 01 Feb 10 nicklas 186       handler.handleEvent(DATA_EVENT, data, this);
5227 01 Feb 10 nicklas 187       tmp = masterParser.nextData();
5227 01 Feb 10 nicklas 188     }
5227 01 Feb 10 nicklas 189     handler.handleEvent(DataParser.END_OF_FILE_EVENT, null, this);
5227 01 Feb 10 nicklas 190   }
5227 01 Feb 10 nicklas 191   
5227 01 Feb 10 nicklas 192   /**
5227 01 Feb 10 nicklas 193     This class holds information that is sent to the event
5227 01 Feb 10 nicklas 194     handler when {@link SynchronizedSpotDataParser#DATA_EVENT}:s are
5227 01 Feb 10 nicklas 195     sent. Each instance contains information about the underlying 
5227 01 Feb 10 nicklas 196     parser (master parser or data parser) and the data on the
5227 01 Feb 10 nicklas 197     line that is currently being processed.
5227 01 Feb 10 nicklas 198     NOTE! There is usually only one instance of this class for 
5227 01 Feb 10 nicklas 199     each parser. If the event handler needs to collect information
5227 01 Feb 10 nicklas 200     accross multiple lines the data should be copied to the event
5227 01 Feb 10 nicklas 201     handler.
5227 01 Feb 10 nicklas 202   */
5227 01 Feb 10 nicklas 203   public static class SynchronizedData
5227 01 Feb 10 nicklas 204   {
5227 01 Feb 10 nicklas 205     private final BfsParser parser;
5227 01 Feb 10 nicklas 206     private String[] data;
5227 01 Feb 10 nicklas 207   
5227 01 Feb 10 nicklas 208     SynchronizedData(BfsParser parser)
5227 01 Feb 10 nicklas 209     {
5227 01 Feb 10 nicklas 210       this.parser = parser;
5227 01 Feb 10 nicklas 211     }
5227 01 Feb 10 nicklas 212     
5227 01 Feb 10 nicklas 213     void setData(String[] data)
5227 01 Feb 10 nicklas 214     {
5227 01 Feb 10 nicklas 215       this.data = data;
5227 01 Feb 10 nicklas 216     }
5227 01 Feb 10 nicklas 217     
5227 01 Feb 10 nicklas 218     /**
5227 01 Feb 10 nicklas 219       Get the current data line, split into columns.
5227 01 Feb 10 nicklas 220     */
5227 01 Feb 10 nicklas 221     public String[] getData()
5227 01 Feb 10 nicklas 222     {
5227 01 Feb 10 nicklas 223       return data;
5227 01 Feb 10 nicklas 224     }
5227 01 Feb 10 nicklas 225     
5227 01 Feb 10 nicklas 226     /**
5227 01 Feb 10 nicklas 227       The underlying parser.
5227 01 Feb 10 nicklas 228     */
5227 01 Feb 10 nicklas 229     public BfsParser getParser()
5227 01 Feb 10 nicklas 230     {
5227 01 Feb 10 nicklas 231       return parser;
5227 01 Feb 10 nicklas 232     }
5227 01 Feb 10 nicklas 233   }
5227 01 Feb 10 nicklas 234   
5227 01 Feb 10 nicklas 235 }