plugins/base2/net.sf.basedb.illumina/trunk/src/net/sf/basedb/illumina/plugins/BgxReporterImporter.java

Code
Comments
Other
Rev Date Author Line
556 28 Jan 08 nicklas 1 /**
646 10 Apr 08 jari 2   $Id$
556 28 Jan 08 nicklas 3
646 10 Apr 08 jari 4   Copyright (C) 2008 Nicklas Nordborg
556 28 Jan 08 nicklas 5
556 28 Jan 08 nicklas 6   This file is part of Illumina plug-in package for BASE.
556 28 Jan 08 nicklas 7   Available at http://baseplugins.thep.lu.se/
556 28 Jan 08 nicklas 8   BASE main site: http://base.thep.lu.se/
556 28 Jan 08 nicklas 9
941 27 Jan 09 martin 10   This is a free software; you can redistribute it and/or modify it
940 27 Jan 09 martin 11   under the terms of the GNU General Public License as published by
940 27 Jan 09 martin 12   the Free Software Foundation; either version 3 of the License, or
940 27 Jan 09 martin 13   (at your option) any later version.
940 27 Jan 09 martin 14    
941 27 Jan 09 martin 15   This software is distributed in the hope that it will be useful, but
940 27 Jan 09 martin 16   WITHOUT ANY WARRANTY; without even the implied warranty of
940 27 Jan 09 martin 17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
940 27 Jan 09 martin 18   General Public License for more details.
940 27 Jan 09 martin 19   
556 28 Jan 08 nicklas 20   You should have received a copy of the GNU General Public License
940 27 Jan 09 martin 21   along with BASE. If not, see <http://www.gnu.org/licenses/>.
556 28 Jan 08 nicklas 22 */
556 28 Jan 08 nicklas 23 package net.sf.basedb.illumina.plugins;
556 28 Jan 08 nicklas 24
556 28 Jan 08 nicklas 25 import java.io.IOException;
556 28 Jan 08 nicklas 26 import java.io.InputStream;
556 28 Jan 08 nicklas 27 import java.io.PushbackInputStream;
586 18 Feb 08 nicklas 28 import java.nio.charset.Charset;
556 28 Jan 08 nicklas 29 import java.util.HashMap;
559 29 Jan 08 nicklas 30 import java.util.List;
556 28 Jan 08 nicklas 31 import java.util.Map;
556 28 Jan 08 nicklas 32 import java.util.regex.Pattern;
556 28 Jan 08 nicklas 33 import java.util.zip.GZIPInputStream;
556 28 Jan 08 nicklas 34
556 28 Jan 08 nicklas 35 import net.sf.basedb.core.BaseException;
559 29 Jan 08 nicklas 36 import net.sf.basedb.core.InvalidDataException;
559 29 Jan 08 nicklas 37 import net.sf.basedb.core.Job;
559 29 Jan 08 nicklas 38 import net.sf.basedb.core.ParameterType;
559 29 Jan 08 nicklas 39 import net.sf.basedb.core.PermissionDeniedException;
559 29 Jan 08 nicklas 40 import net.sf.basedb.core.PluginConfiguration;
559 29 Jan 08 nicklas 41 import net.sf.basedb.core.PluginDefinition;
559 29 Jan 08 nicklas 42 import net.sf.basedb.core.SessionControl;
556 28 Jan 08 nicklas 43 import net.sf.basedb.core.plugin.InteractivePlugin;
559 29 Jan 08 nicklas 44 import net.sf.basedb.core.plugin.ParameterValues;
556 28 Jan 08 nicklas 45 import net.sf.basedb.plugins.ReporterFlatFileImporter;
556 28 Jan 08 nicklas 46 import net.sf.basedb.util.FileUtil;
556 28 Jan 08 nicklas 47 import net.sf.basedb.util.InputStreamTracker;
556 28 Jan 08 nicklas 48 import net.sf.basedb.util.parser.FlatFileParser;
1385 02 Sep 11 martin 49 import net.sf.basedb.util.parser.FlatFileParser.Line;
556 28 Jan 08 nicklas 50 import net.sf.basedb.util.parser.WrappedConfigureByExample;
556 28 Jan 08 nicklas 51
556 28 Jan 08 nicklas 52 /**
556 28 Jan 08 nicklas 53   Plug-in that import reporter annotations from Illumina BGX files. 
556 28 Jan 08 nicklas 54   It supports both compressed (gzip) and uncompressed BGX files.
556 28 Jan 08 nicklas 55   <p>
556 28 Jan 08 nicklas 56   Most functionality is provided by the {@link ReporterFlatFileImporter}.
556 28 Jan 08 nicklas 57   This subclass adds support for decompressing a compressed BGX file
559 29 Jan 08 nicklas 58   and for parsing the second section with control probes. Currently,
559 29 Jan 08 nicklas 59   only the annotations for the [Probes] section are configurable, the
559 29 Jan 08 nicklas 60   regular expressions and column mappings for the [Controls] section 
559 29 Jan 08 nicklas 61   is hardcoded into this class as follows:
559 29 Jan 08 nicklas 62   
559 29 Jan 08 nicklas 63   <pre class="code">
559 29 Jan 08 nicklas 64 dataHeaderRegexp               --&gt; Probe_Id\tArray_Address_Id.*
559 29 Jan 08 nicklas 65 minDataColumns                 --&gt; 3
559 29 Jan 08 nicklas 66 reporterIdColumnMapping        --&gt; \Probe_Id\
559 29 Jan 08 nicklas 67 nameColumnMapping              --&gt; \Probe_Id\
559 29 Jan 08 nicklas 68 extendedColumnMapping.sequence --&gt; \Probe_Sequence\
559 29 Jan 08 nicklas 69 </pre>
556 28 Jan 08 nicklas 70 */
556 28 Jan 08 nicklas 71 public class BgxReporterImporter 
556 28 Jan 08 nicklas 72   extends ReporterFlatFileImporter
556 28 Jan 08 nicklas 73   implements InteractivePlugin, WrappedConfigureByExample
556 28 Jan 08 nicklas 74 {
556 28 Jan 08 nicklas 75   
556 28 Jan 08 nicklas 76   /**
556 28 Jan 08 nicklas 77     Needed for progress reporting when reading from a compressed
556 28 Jan 08 nicklas 78     BGX file.
556 28 Jan 08 nicklas 79   */
556 28 Jan 08 nicklas 80   private InputStreamTracker tracker;
556 28 Jan 08 nicklas 81   
556 28 Jan 08 nicklas 82   /**
556 28 Jan 08 nicklas 83     The parser we are using.
556 28 Jan 08 nicklas 84   */
556 28 Jan 08 nicklas 85   private FlatFileParser ffp;
556 28 Jan 08 nicklas 86   
556 28 Jan 08 nicklas 87   /**
556 28 Jan 08 nicklas 88     The section we are currently parsing.
556 28 Jan 08 nicklas 89   */
556 28 Jan 08 nicklas 90   private Section currentSection;
556 28 Jan 08 nicklas 91   
1187 11 Feb 10 nicklas 92   private ParameterValuesProxy jobParameterProxy;
559 29 Jan 08 nicklas 93   
556 28 Jan 08 nicklas 94   public BgxReporterImporter()
556 28 Jan 08 nicklas 95   {}
556 28 Jan 08 nicklas 96   
556 28 Jan 08 nicklas 97   /*
556 28 Jan 08 nicklas 98     From the Plugin interface
556 28 Jan 08 nicklas 99     -------------------------------------------
556 28 Jan 08 nicklas 100   */
556 28 Jan 08 nicklas 101   @Override
559 29 Jan 08 nicklas 102   public void init(SessionControl sc, ParameterValues configuration, ParameterValues job)
559 29 Jan 08 nicklas 103   {
1187 11 Feb 10 nicklas 104     this.jobParameterProxy = job == null ? null : new ParameterValuesProxy(job);
1187 11 Feb 10 nicklas 105     super.init(sc, configuration, this.jobParameterProxy);
559 29 Jan 08 nicklas 106   }
556 28 Jan 08 nicklas 107   // -------------------------------------------
556 28 Jan 08 nicklas 108
556 28 Jan 08 nicklas 109   /*
559 29 Jan 08 nicklas 110     From the WrappedConfigureByExample interface
556 28 Jan 08 nicklas 111     -------------------------------------------
556 28 Jan 08 nicklas 112   */
556 28 Jan 08 nicklas 113   /**
556 28 Jan 08 nicklas 114     If the input stream is a gzip:ed stream, wraps it in a GZIPInputStream.
556 28 Jan 08 nicklas 115   */
556 28 Jan 08 nicklas 116   @Override
556 28 Jan 08 nicklas 117   public InputStream wrapInputStream(InputStream in)
556 28 Jan 08 nicklas 118     throws IOException
556 28 Jan 08 nicklas 119   {
556 28 Jan 08 nicklas 120     tracker = new InputStreamTracker(in);
556 28 Jan 08 nicklas 121     PushbackInputStream pin = new PushbackInputStream(tracker, 2);
556 28 Jan 08 nicklas 122     boolean isGzip = FileUtil.checkMagicNumber(pin, new byte[] { 0x1f, (byte)0x8b });
556 28 Jan 08 nicklas 123     if (isGzip)
556 28 Jan 08 nicklas 124     {
556 28 Jan 08 nicklas 125       in = new GZIPInputStream(pin);
556 28 Jan 08 nicklas 126     }
556 28 Jan 08 nicklas 127     else
556 28 Jan 08 nicklas 128     {
556 28 Jan 08 nicklas 129       in = pin;
556 28 Jan 08 nicklas 130     }
586 18 Feb 08 nicklas 131     return new BgxMergeControlsInputStream(in, Charset.forName(getCharset()));
556 28 Jan 08 nicklas 132   }
559 29 Jan 08 nicklas 133   // -------------------------------------------
556 28 Jan 08 nicklas 134   
559 29 Jan 08 nicklas 135   /*
559 29 Jan 08 nicklas 136     From the AbstractFlatFileImporter class
559 29 Jan 08 nicklas 137     -------------------------------------------
559 29 Jan 08 nicklas 138   */
556 28 Jan 08 nicklas 139   /**
556 28 Jan 08 nicklas 140     Get the number of byte from the compressed file.
556 28 Jan 08 nicklas 141   */
556 28 Jan 08 nicklas 142   @Override
556 28 Jan 08 nicklas 143   protected long getNumBytes(FlatFileParser ffp)
556 28 Jan 08 nicklas 144   {
556 28 Jan 08 nicklas 145     return tracker.getNumRead();
556 28 Jan 08 nicklas 146   }
556 28 Jan 08 nicklas 147   
556 28 Jan 08 nicklas 148   /**
556 28 Jan 08 nicklas 149     We need to set the regular expression for matching each new section.
556 28 Jan 08 nicklas 150     Temporarily we also hard-code the other regular expressions that need to
556 28 Jan 08 nicklas 151     be configurable.
556 28 Jan 08 nicklas 152   */
556 28 Jan 08 nicklas 153   @Override
556 28 Jan 08 nicklas 154   protected FlatFileParser getInitializedFlatFileParser()
556 28 Jan 08 nicklas 155     throws BaseException 
556 28 Jan 08 nicklas 156   {
556 28 Jan 08 nicklas 157     ffp = super.getInitializedFlatFileParser();
556 28 Jan 08 nicklas 158     ffp.setSectionRegexp(Pattern.compile("\\[(.+)\\]"));
556 28 Jan 08 nicklas 159     return ffp;
556 28 Jan 08 nicklas 160   }
556 28 Jan 08 nicklas 161
559 29 Jan 08 nicklas 162   /**
1146 31 Jul 09 nicklas 163     The default {@link #isImportable()} method only looks in the first
1146 31 Jul 09 nicklas 164     section. In BGX files data is in the second section. So, if the
1146 31 Jul 09 nicklas 165     last found line is the [Probes] section we should continue to
1146 31 Jul 09 nicklas 166     parse and check if we find the data header.
1146 31 Jul 09 nicklas 167     @since 1.4
1146 31 Jul 09 nicklas 168   */
1146 31 Jul 09 nicklas 169   @Override
1146 31 Jul 09 nicklas 170   protected boolean isImportable(FlatFileParser ffp) 
1146 31 Jul 09 nicklas 171     throws IOException 
1146 31 Jul 09 nicklas 172   {
1146 31 Jul 09 nicklas 173     boolean importable = false;
1146 31 Jul 09 nicklas 174     Line last = ffp.getLine(ffp.getLineCount()-1);
1146 31 Jul 09 nicklas 175     if (last.type() == FlatFileParser.LineType.SECTION && 
1146 31 Jul 09 nicklas 176         Section.getByName(last.name()) == Section.PROBES)
1146 31 Jul 09 nicklas 177     {
1146 31 Jul 09 nicklas 178       importable = ffp.parseHeaders() == FlatFileParser.LineType.DATA_HEADER;
1146 31 Jul 09 nicklas 179     }
1146 31 Jul 09 nicklas 180     return importable;
1146 31 Jul 09 nicklas 181   }
1146 31 Jul 09 nicklas 182   
1146 31 Jul 09 nicklas 183   /**
575 07 Feb 08 martin 184     When we get to the [Controls] section, we change configuration parameters
559 29 Jan 08 nicklas 185     for the parser and column mappings.
559 29 Jan 08 nicklas 186     @see ParameterValuesProxy
559 29 Jan 08 nicklas 187   */
556 28 Jan 08 nicklas 188   @Override
556 28 Jan 08 nicklas 189   protected void handleSection(Line line) 
556 28 Jan 08 nicklas 190     throws BaseException 
556 28 Jan 08 nicklas 191   {
556 28 Jan 08 nicklas 192     currentSection = Section.getByName(line.name());
556 28 Jan 08 nicklas 193     if (currentSection == Section.CONTROLS)
556 28 Jan 08 nicklas 194     {
556 28 Jan 08 nicklas 195       // Change regular expressions to match the data in this section
556 28 Jan 08 nicklas 196       ffp.setDataHeaderRegexp(Pattern.compile("Probe_Id\\tArray_Address_Id.*"));
559 29 Jan 08 nicklas 197       ffp.setMinDataColumns(3);
556 28 Jan 08 nicklas 198       ffp.setIgnoreNonExistingColumns(true);
559 29 Jan 08 nicklas 199       Map<String, Object> override = new HashMap<String, Object>();
559 29 Jan 08 nicklas 200       override.put("reporterIdColumnMapping", "\\Probe_Id\\");
559 29 Jan 08 nicklas 201       override.put("nameColumnMapping", "\\Probe_Id\\");
559 29 Jan 08 nicklas 202       override.put("extendedColumnMapping.sequence", "\\Probe_Sequence\\");
575 07 Feb 08 martin 203       override.put("extendedColumnMapping.controlGroupName", "\\Reporter_Group_Name\\");
575 07 Feb 08 martin 204       override.put("extendedColumnMapping.controlGroupId", "\\Reporter_Group_id\\");
575 07 Feb 08 martin 205       override.put("extendedColumnMapping.controlCompositeMap", "\\Reporter_Composite_map\\");
1187 11 Feb 10 nicklas 206       jobParameterProxy.setOverride(override);
556 28 Jan 08 nicklas 207     }
559 29 Jan 08 nicklas 208     else
559 29 Jan 08 nicklas 209     {
1187 11 Feb 10 nicklas 210       jobParameterProxy.setOverride(null);
559 29 Jan 08 nicklas 211     }
556 28 Jan 08 nicklas 212   }
556 28 Jan 08 nicklas 213   // -------------------------------------------
556 28 Jan 08 nicklas 214
559 29 Jan 08 nicklas 215   /**
559 29 Jan 08 nicklas 216     Keep track of which section we are currently parsing. We only need to
559 29 Jan 08 nicklas 217     know if we are in the [Probes] or [Controls] section.
559 29 Jan 08 nicklas 218   */
556 28 Jan 08 nicklas 219   private enum Section
556 28 Jan 08 nicklas 220   {
556 28 Jan 08 nicklas 221     PROBES("Probes"),
556 28 Jan 08 nicklas 222     CONTROLS("Controls"),
556 28 Jan 08 nicklas 223     OTHER(null);
556 28 Jan 08 nicklas 224     
556 28 Jan 08 nicklas 225     private static final Map<String, Section> sections = new HashMap<String, Section>();
556 28 Jan 08 nicklas 226     static
556 28 Jan 08 nicklas 227     {
556 28 Jan 08 nicklas 228       for (Section s : Section.values())
556 28 Jan 08 nicklas 229       {
556 28 Jan 08 nicklas 230         sections.put(s.name, s);
556 28 Jan 08 nicklas 231       }
556 28 Jan 08 nicklas 232     }
556 28 Jan 08 nicklas 233     
556 28 Jan 08 nicklas 234     private String name;
556 28 Jan 08 nicklas 235     private Section(String name)
556 28 Jan 08 nicklas 236     {
556 28 Jan 08 nicklas 237       this.name = name;
556 28 Jan 08 nicklas 238     }
556 28 Jan 08 nicklas 239     
556 28 Jan 08 nicklas 240     
556 28 Jan 08 nicklas 241     private static Section getByName(String name)
556 28 Jan 08 nicklas 242     {
556 28 Jan 08 nicklas 243       Section s = sections.get(name);
556 28 Jan 08 nicklas 244       if (s == null) s = Section.OTHER;
556 28 Jan 08 nicklas 245       return s;
556 28 Jan 08 nicklas 246     }
559 29 Jan 08 nicklas 247   }
559 29 Jan 08 nicklas 248   
559 29 Jan 08 nicklas 249   /**
559 29 Jan 08 nicklas 250     Proxy for the plugin configuration parameters. Forwards
559 29 Jan 08 nicklas 251     everything to the original parameters, except when the
559 29 Jan 08 nicklas 252     'override' is set and then only for 'ColumnMapping' parameters.
559 29 Jan 08 nicklas 253     This is needed so we can use different column mappings when parsing
559 29 Jan 08 nicklas 254     the [Controls] section of the BGX file. The regular configuration
559 29 Jan 08 nicklas 255     parameters only apply to the [Probes] section.
559 29 Jan 08 nicklas 256   */
559 29 Jan 08 nicklas 257   private static class ParameterValuesProxy
559 29 Jan 08 nicklas 258     implements ParameterValues
559 29 Jan 08 nicklas 259   {
556 28 Jan 08 nicklas 260     
559 29 Jan 08 nicklas 261     private ParameterValues params;
559 29 Jan 08 nicklas 262     private Map<String, Object> override;
559 29 Jan 08 nicklas 263     
559 29 Jan 08 nicklas 264     private ParameterValuesProxy(ParameterValues params)
559 29 Jan 08 nicklas 265     {
559 29 Jan 08 nicklas 266       this.params = params;
559 29 Jan 08 nicklas 267     }
559 29 Jan 08 nicklas 268     
559 29 Jan 08 nicklas 269     /*
559 29 Jan 08 nicklas 270       From the ParameterValues interface
559 29 Jan 08 nicklas 271       -------------------------------------------
559 29 Jan 08 nicklas 272     */
559 29 Jan 08 nicklas 273     @Override
559 29 Jan 08 nicklas 274     public int getId() 
559 29 Jan 08 nicklas 275     {
559 29 Jan 08 nicklas 276       return params.getId();
559 29 Jan 08 nicklas 277     }
559 29 Jan 08 nicklas 278     @Override
559 29 Jan 08 nicklas 279     public Job getJob() 
559 29 Jan 08 nicklas 280     {
559 29 Jan 08 nicklas 281       return params.getJob();
559 29 Jan 08 nicklas 282     }
559 29 Jan 08 nicklas 283     @Override
559 29 Jan 08 nicklas 284     public PluginConfiguration getPluginConfiguration() 
559 29 Jan 08 nicklas 285     {
559 29 Jan 08 nicklas 286       return params.getPluginConfiguration();
559 29 Jan 08 nicklas 287     }
559 29 Jan 08 nicklas 288     @Override
559 29 Jan 08 nicklas 289     public PluginDefinition getPluginDefinition() 
559 29 Jan 08 nicklas 290     {
559 29 Jan 08 nicklas 291       return params.getPluginDefinition();
559 29 Jan 08 nicklas 292     }
559 29 Jan 08 nicklas 293     @Override
559 29 Jan 08 nicklas 294     public Object getValue(String name) 
559 29 Jan 08 nicklas 295       throws PermissionDeniedException, BaseException 
559 29 Jan 08 nicklas 296     {
559 29 Jan 08 nicklas 297       return override != null && name.contains("ColumnMapping") ? 
559 29 Jan 08 nicklas 298         override.get(name) : params.getValue(name);
559 29 Jan 08 nicklas 299     }
559 29 Jan 08 nicklas 300     @Override
559 29 Jan 08 nicklas 301     public List<?> getValues(String name) 
559 29 Jan 08 nicklas 302       throws PermissionDeniedException, BaseException 
559 29 Jan 08 nicklas 303     {
559 29 Jan 08 nicklas 304       return params.getValues(name);
559 29 Jan 08 nicklas 305     }
559 29 Jan 08 nicklas 306     @Override
559 29 Jan 08 nicklas 307     public <T> void setValue(String name, ParameterType<T> type, T value)
559 29 Jan 08 nicklas 308       throws PermissionDeniedException, InvalidDataException, BaseException 
559 29 Jan 08 nicklas 309     {
559 29 Jan 08 nicklas 310       params.setValue(name, type, value);
559 29 Jan 08 nicklas 311     }
559 29 Jan 08 nicklas 312     @Override
559 29 Jan 08 nicklas 313     public <T> void setValues(String name, ParameterType<T> type, List<T> values) 
559 29 Jan 08 nicklas 314       throws PermissionDeniedException, InvalidDataException, BaseException 
559 29 Jan 08 nicklas 315     {
559 29 Jan 08 nicklas 316       params.setValues(name, type, values);
559 29 Jan 08 nicklas 317     }
559 29 Jan 08 nicklas 318     // -------------------------------------------
559 29 Jan 08 nicklas 319     
559 29 Jan 08 nicklas 320     private void setOverride(Map<String, Object> override)
559 29 Jan 08 nicklas 321     {
559 29 Jan 08 nicklas 322       this.override = override;
559 29 Jan 08 nicklas 323     }
559 29 Jan 08 nicklas 324     
559 29 Jan 08 nicklas 325   }
559 29 Jan 08 nicklas 326   
559 29 Jan 08 nicklas 327   
559 29 Jan 08 nicklas 328   
556 28 Jan 08 nicklas 329 }
556 28 Jan 08 nicklas 330
556 28 Jan 08 nicklas 331
556 28 Jan 08 nicklas 332
556 28 Jan 08 nicklas 333