extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/AbstractPlateImporter.java

Code
Comments
Other
Rev Date Author Line
3835 11 Apr 16 nicklas 1 package net.sf.basedb.reggie.plugins;
3835 11 Apr 16 nicklas 2
3835 11 Apr 16 nicklas 3 import java.util.ArrayList;
3835 11 Apr 16 nicklas 4 import java.util.HashMap;
3835 11 Apr 16 nicklas 5 import java.util.HashSet;
3835 11 Apr 16 nicklas 6 import java.util.IdentityHashMap;
3835 11 Apr 16 nicklas 7 import java.util.LinkedHashSet;
3835 11 Apr 16 nicklas 8 import java.util.List;
3835 11 Apr 16 nicklas 9 import java.util.Map;
3835 11 Apr 16 nicklas 10 import java.util.Set;
3835 11 Apr 16 nicklas 11
3835 11 Apr 16 nicklas 12 import net.sf.basedb.core.AnnotationType;
3835 11 Apr 16 nicklas 13 import net.sf.basedb.core.AnyToAny;
3835 11 Apr 16 nicklas 14 import net.sf.basedb.core.BioPlate;
3835 11 Apr 16 nicklas 15 import net.sf.basedb.core.BioWell;
3835 11 Apr 16 nicklas 16 import net.sf.basedb.core.DbControl;
3835 11 Apr 16 nicklas 17 import net.sf.basedb.core.Extract;
3835 11 Apr 16 nicklas 18 import net.sf.basedb.core.File;
3835 11 Apr 16 nicklas 19 import net.sf.basedb.core.ItemQuery;
3835 11 Apr 16 nicklas 20 import net.sf.basedb.core.Type;
3835 11 Apr 16 nicklas 21 import net.sf.basedb.core.query.Expressions;
3835 11 Apr 16 nicklas 22 import net.sf.basedb.core.query.Hql;
3835 11 Apr 16 nicklas 23 import net.sf.basedb.core.query.Orders;
3835 11 Apr 16 nicklas 24 import net.sf.basedb.core.query.Restrictions;
3835 11 Apr 16 nicklas 25 import net.sf.basedb.reggie.converter.ValueConverter;
3835 11 Apr 16 nicklas 26 import net.sf.basedb.util.Coordinate;
3835 11 Apr 16 nicklas 27 import net.sf.basedb.util.Values;
3835 11 Apr 16 nicklas 28
3835 11 Apr 16 nicklas 29 /**
3835 11 Apr 16 nicklas 30   Abstract base class for some common functionality used
3835 11 Apr 16 nicklas 31   by the Caliper and Qubit importers.
3835 11 Apr 16 nicklas 32   
3835 11 Apr 16 nicklas 33   @author nicklas
3835 11 Apr 16 nicklas 34   @since 4.3
3835 11 Apr 16 nicklas 35 */
3835 11 Apr 16 nicklas 36 public abstract class AbstractPlateImporter
3835 11 Apr 16 nicklas 37 {
3835 11 Apr 16 nicklas 38
3835 11 Apr 16 nicklas 39   
3835 11 Apr 16 nicklas 40   private final Map<String, AnnotationType> annotations;
3835 11 Apr 16 nicklas 41   private final Map<String, ValueConverter<String, ?>> converters;
3835 11 Apr 16 nicklas 42   private final Map<ValueConverter<String, ?>, AnnotationType> externalLookup;
3835 11 Apr 16 nicklas 43   private final Set<Extract> extracts;
3835 11 Apr 16 nicklas 44   private Set<Extract> missingExtracts;
3835 11 Apr 16 nicklas 45   private final List<String> errorMessages;
3835 11 Apr 16 nicklas 46   private final List<String> externalErrorMessages;
3835 11 Apr 16 nicklas 47   private final List<String> warningMessages;
3835 11 Apr 16 nicklas 48
3835 11 Apr 16 nicklas 49   private boolean allowMatchAgainstLocation;
3835 11 Apr 16 nicklas 50   private int numImported;
3835 11 Apr 16 nicklas 51   private BioPlate plate;
3835 11 Apr 16 nicklas 52   
3835 11 Apr 16 nicklas 53   public AbstractPlateImporter()
3835 11 Apr 16 nicklas 54   {
3835 11 Apr 16 nicklas 55     this.annotations = new HashMap<String, AnnotationType>();
3835 11 Apr 16 nicklas 56     this.converters = new HashMap<String, ValueConverter<String, ?>>();
3835 11 Apr 16 nicklas 57     this.externalLookup = new IdentityHashMap<ValueConverter<String, ?>, AnnotationType>();
3835 11 Apr 16 nicklas 58     this.errorMessages = new ArrayList<String>();
3835 11 Apr 16 nicklas 59     this.externalErrorMessages = new ArrayList<String>();
3835 11 Apr 16 nicklas 60     this.warningMessages = new ArrayList<String>();
3835 11 Apr 16 nicklas 61     this.extracts = new HashSet<Extract>();
3835 11 Apr 16 nicklas 62     this.missingExtracts = new HashSet<Extract>();
3835 11 Apr 16 nicklas 63   }
3835 11 Apr 16 nicklas 64   
3835 11 Apr 16 nicklas 65   /**
3835 11 Apr 16 nicklas 66     Set the bioplate to use by the importer.
3835 11 Apr 16 nicklas 67     @param plate The Bioplate
3835 11 Apr 16 nicklas 68   */
3835 11 Apr 16 nicklas 69   public void setBioPlate(BioPlate plate)
3835 11 Apr 16 nicklas 70   {
3835 11 Apr 16 nicklas 71     this.plate = plate;
3835 11 Apr 16 nicklas 72   }
3835 11 Apr 16 nicklas 73   
3835 11 Apr 16 nicklas 74   /**
3835 11 Apr 16 nicklas 75     Get the bioplate that this importer is importing data to.
3835 11 Apr 16 nicklas 76   */
3835 11 Apr 16 nicklas 77   public BioPlate getBioPlate()
3835 11 Apr 16 nicklas 78   {
3835 11 Apr 16 nicklas 79     return plate;
3835 11 Apr 16 nicklas 80   }
3835 11 Apr 16 nicklas 81   
3835 11 Apr 16 nicklas 82   /**
3835 11 Apr 16 nicklas 83     If this option is set, the values in the 'Sample Name' column are
3835 11 Apr 16 nicklas 84     allowed to be location coordinates (if not too many).
3835 11 Apr 16 nicklas 85   */
3835 11 Apr 16 nicklas 86   public void setAllowMatchAgainstLocation(boolean allow)
3835 11 Apr 16 nicklas 87   {
3835 11 Apr 16 nicklas 88     this.allowMatchAgainstLocation = allow;
3835 11 Apr 16 nicklas 89   }
3835 11 Apr 16 nicklas 90   
3835 11 Apr 16 nicklas 91   public boolean allowMatchAgainstLocation()
3835 11 Apr 16 nicklas 92   {
3835 11 Apr 16 nicklas 93     return allowMatchAgainstLocation;
3835 11 Apr 16 nicklas 94   }
3835 11 Apr 16 nicklas 95   
3835 11 Apr 16 nicklas 96   /**
3835 11 Apr 16 nicklas 97     Map a column to an annotation type.
3835 11 Apr 16 nicklas 98     @param column
3835 11 Apr 16 nicklas 99      @param annotation
3835 11 Apr 16 nicklas 100      @param converter Optional converter that take the string value for the given column as input
3835 11 Apr 16 nicklas 101        and return either value of the correct class or a string which will be converted
3835 11 Apr 16 nicklas 102        using {@link Type#parseString(String)}.
3835 11 Apr 16 nicklas 103   */
3835 11 Apr 16 nicklas 104   public void setAnnotationMapping(String column, AnnotationType annotation, ValueConverter<String, ?> converter)
3835 11 Apr 16 nicklas 105   {
3835 11 Apr 16 nicklas 106     this.annotations.put(column, annotation);
3835 11 Apr 16 nicklas 107     this.converters.put(column, converter);
3835 11 Apr 16 nicklas 108   }
3835 11 Apr 16 nicklas 109   
3835 11 Apr 16 nicklas 110   protected Map<String, AnnotationType> getAnnotationMappings()
3835 11 Apr 16 nicklas 111   {
3835 11 Apr 16 nicklas 112     return annotations;
3835 11 Apr 16 nicklas 113   }
3835 11 Apr 16 nicklas 114   
3835 11 Apr 16 nicklas 115   protected Map<String, ValueConverter<String, ?>> getColumnConverters()
3835 11 Apr 16 nicklas 116   {
3835 11 Apr 16 nicklas 117     return converters;
3835 11 Apr 16 nicklas 118   }
3835 11 Apr 16 nicklas 119   
3835 11 Apr 16 nicklas 120   /**
3835 11 Apr 16 nicklas 121     Add an external lookup converter to find annotation values for the given annotation.
3835 11 Apr 16 nicklas 122     The converter should take as input the sample name on the current row and return
3835 11 Apr 16 nicklas 123     the looked up value, which may be either an object of the correct class or a
3835 11 Apr 16 nicklas 124     string which will be converted using {@link Type#parseString(String)}.
3835 11 Apr 16 nicklas 125     @param lookup
3835 11 Apr 16 nicklas 126     @param annotation
3835 11 Apr 16 nicklas 127   */
3835 11 Apr 16 nicklas 128   public void addExternalLookup(ValueConverter<String, ?> lookup, AnnotationType annotation)
3835 11 Apr 16 nicklas 129   {
3835 11 Apr 16 nicklas 130     this.externalLookup.put(lookup, annotation);
3835 11 Apr 16 nicklas 131   }
3835 11 Apr 16 nicklas 132   
3835 11 Apr 16 nicklas 133   protected Map<ValueConverter<String, ?>, AnnotationType> getExternalLookups()
3835 11 Apr 16 nicklas 134   {
3835 11 Apr 16 nicklas 135     return externalLookup;
3835 11 Apr 16 nicklas 136   }
3835 11 Apr 16 nicklas 137   
3835 11 Apr 16 nicklas 138   protected void reset()
3835 11 Apr 16 nicklas 139   {
3835 11 Apr 16 nicklas 140     numImported = 0;
3835 11 Apr 16 nicklas 141     errorMessages.clear();
3835 11 Apr 16 nicklas 142     externalErrorMessages.clear();
3835 11 Apr 16 nicklas 143     warningMessages.clear();
3835 11 Apr 16 nicklas 144     extracts.clear();
3835 11 Apr 16 nicklas 145     missingExtracts.clear();
3835 11 Apr 16 nicklas 146   }
3835 11 Apr 16 nicklas 147   
3835 11 Apr 16 nicklas 148   public boolean hasWarning()
3835 11 Apr 16 nicklas 149   {
3835 11 Apr 16 nicklas 150     return warningMessages.size() > 0;
3835 11 Apr 16 nicklas 151   }
3835 11 Apr 16 nicklas 152   
3835 11 Apr 16 nicklas 153   public List<String> getWarningMessages()
3835 11 Apr 16 nicklas 154   {
3835 11 Apr 16 nicklas 155     return warningMessages;
3835 11 Apr 16 nicklas 156   }
3835 11 Apr 16 nicklas 157   
3835 11 Apr 16 nicklas 158   public boolean hasError()
3835 11 Apr 16 nicklas 159   {
3835 11 Apr 16 nicklas 160     return errorMessages.size() > 0;
3835 11 Apr 16 nicklas 161   }
3835 11 Apr 16 nicklas 162   
3835 11 Apr 16 nicklas 163   public List<String> getErrorMessages()
3835 11 Apr 16 nicklas 164   {
3835 11 Apr 16 nicklas 165     return errorMessages;
3835 11 Apr 16 nicklas 166   }
3835 11 Apr 16 nicklas 167   
3835 11 Apr 16 nicklas 168   public List<String> getExternalErrorMessages()
3835 11 Apr 16 nicklas 169   {
3835 11 Apr 16 nicklas 170     return externalErrorMessages;
3835 11 Apr 16 nicklas 171   }
3835 11 Apr 16 nicklas 172   
3835 11 Apr 16 nicklas 173   public boolean hasExternalError()
3835 11 Apr 16 nicklas 174   {
3835 11 Apr 16 nicklas 175     return externalErrorMessages.size() > 0;
3835 11 Apr 16 nicklas 176   }
3835 11 Apr 16 nicklas 177   
3835 11 Apr 16 nicklas 178   public void addWarningMessage(String msg)
3835 11 Apr 16 nicklas 179   {
3835 11 Apr 16 nicklas 180     this.warningMessages.add("[Warning] " + msg);
3835 11 Apr 16 nicklas 181   }
3835 11 Apr 16 nicklas 182   
3835 11 Apr 16 nicklas 183   public void addErrorMessage(String msg)
3835 11 Apr 16 nicklas 184   {
3835 11 Apr 16 nicklas 185     this.errorMessages.add("[Error] " + msg);
3835 11 Apr 16 nicklas 186   }
3835 11 Apr 16 nicklas 187   
3835 11 Apr 16 nicklas 188   public void addExternalErrorMessage(String msg)
3835 11 Apr 16 nicklas 189   {
3835 11 Apr 16 nicklas 190     this.externalErrorMessages.add("[Error] " + msg);
3835 11 Apr 16 nicklas 191   }
3835 11 Apr 16 nicklas 192   
3835 11 Apr 16 nicklas 193   public int getNumImported()
3835 11 Apr 16 nicklas 194   {
3835 11 Apr 16 nicklas 195     return numImported;
3835 11 Apr 16 nicklas 196   }
3835 11 Apr 16 nicklas 197   
3835 11 Apr 16 nicklas 198   protected void addImported()
3835 11 Apr 16 nicklas 199   {
3835 11 Apr 16 nicklas 200     numImported++;
3835 11 Apr 16 nicklas 201   }
3835 11 Apr 16 nicklas 202   
3835 11 Apr 16 nicklas 203   /**
3835 11 Apr 16 nicklas 204     Get all extracts that has been processed by the importer.
3835 11 Apr 16 nicklas 205   */
3835 11 Apr 16 nicklas 206   public Set<Extract> getExtracts()
3835 11 Apr 16 nicklas 207   {
3835 11 Apr 16 nicklas 208     return extracts;
3835 11 Apr 16 nicklas 209   }
3835 11 Apr 16 nicklas 210   
3835 11 Apr 16 nicklas 211   /**
3835 11 Apr 16 nicklas 212     Get all extracts that was found on the plate but hasn't been
3835 11 Apr 16 nicklas 213     processed by the importer
3835 11 Apr 16 nicklas 214   */
3835 11 Apr 16 nicklas 215   public Set<Extract> getMissingExtracts()
3835 11 Apr 16 nicklas 216   {
3835 11 Apr 16 nicklas 217     return missingExtracts;
3835 11 Apr 16 nicklas 218   }
3835 11 Apr 16 nicklas 219   
3835 11 Apr 16 nicklas 220   /**
3835 11 Apr 16 nicklas 221     Attach a file to the plate.
3835 11 Apr 16 nicklas 222   */
3835 11 Apr 16 nicklas 223   public void attachFile(DbControl dc, File file, String name)
3835 11 Apr 16 nicklas 224   {
3835 11 Apr 16 nicklas 225     AnyToAny ata = AnyToAny.getNewOrExisting(dc, plate, name, file, true);
3835 11 Apr 16 nicklas 226     if (!ata.isInDatabase())
3835 11 Apr 16 nicklas 227     {
3835 11 Apr 16 nicklas 228       dc.saveItem(ata);
3835 11 Apr 16 nicklas 229     }
3835 11 Apr 16 nicklas 230     if (file.getDescription() == null)
3835 11 Apr 16 nicklas 231     {
3835 11 Apr 16 nicklas 232       file.setDescription(name + " for " + plate.getName());
3835 11 Apr 16 nicklas 233     }
3835 11 Apr 16 nicklas 234   }
3835 11 Apr 16 nicklas 235   
3835 11 Apr 16 nicklas 236   
3835 11 Apr 16 nicklas 237   /**
3835 11 Apr 16 nicklas 238     Load all extracts on the bioplate.
3835 11 Apr 16 nicklas 239   */
3835 11 Apr 16 nicklas 240   protected Set<Extract> loadExtractsOnPlate(DbControl dc, BioPlate plate)
3835 11 Apr 16 nicklas 241   {
3835 11 Apr 16 nicklas 242     ItemQuery<Extract> query = Extract.getQuery();
3835 11 Apr 16 nicklas 243     query.join(Hql.innerJoin("bioWell", "bw"));
3835 11 Apr 16 nicklas 244     query.restrict(Restrictions.eq(Hql.property("bw", "bioPlate"), Expressions.integer(plate.getId())));
3835 11 Apr 16 nicklas 245     query.order(Orders.asc(Hql.property("bw", "row")));
3835 11 Apr 16 nicklas 246     query.order(Orders.asc(Hql.property("bw", "column")));
3835 11 Apr 16 nicklas 247     return new LinkedHashSet<Extract>(query.list(dc));
3835 11 Apr 16 nicklas 248   }
3835 11 Apr 16 nicklas 249   
3835 11 Apr 16 nicklas 250   /**
3835 11 Apr 16 nicklas 251     Find an extract with a given name on a bioplate.
3835 11 Apr 16 nicklas 252   */
3835 11 Apr 16 nicklas 253   protected Extract findExtractByName(DbControl dc, BioPlate plate, String name, String location, String fileAndLine)
3835 11 Apr 16 nicklas 254   {
3835 11 Apr 16 nicklas 255     ItemQuery<Extract> query = Extract.getQuery();
3835 11 Apr 16 nicklas 256     query.restrict(Restrictions.eq(Hql.property("name"), Expressions.string(name)));
3835 11 Apr 16 nicklas 257     if (plate != null)
3835 11 Apr 16 nicklas 258     {
3835 11 Apr 16 nicklas 259       query.restrict(Restrictions.eq(Hql.property("bioWell.bioPlate"), Expressions.integer(plate.getId())));
3835 11 Apr 16 nicklas 260     }
3835 11 Apr 16 nicklas 261     
3835 11 Apr 16 nicklas 262     List<Extract> list = query.list(dc);
3835 11 Apr 16 nicklas 263     Extract extract = null;
3835 11 Apr 16 nicklas 264     if (list.size() == 0)
3835 11 Apr 16 nicklas 265     {
3835 11 Apr 16 nicklas 266       addErrorMessage(fileAndLine + "Could not find any extract with name '" + name + "' on plate " + 
3835 11 Apr 16 nicklas 267         plate.getName() + "[" + location + "]");
3835 11 Apr 16 nicklas 268     }
3835 11 Apr 16 nicklas 269     else if (list.size() > 1)
3835 11 Apr 16 nicklas 270     {
3835 11 Apr 16 nicklas 271       addErrorMessage(fileAndLine + "Found " + list.size() + " extracts with the same name '" + name + "' on plate " + 
3835 11 Apr 16 nicklas 272         plate.getName() + "[" + location + "]");
3835 11 Apr 16 nicklas 273     }
3835 11 Apr 16 nicklas 274     else
3835 11 Apr 16 nicklas 275     {
3835 11 Apr 16 nicklas 276       extract = list.get(0);
3835 11 Apr 16 nicklas 277     }
3835 11 Apr 16 nicklas 278     
3835 11 Apr 16 nicklas 279     return extract;
3835 11 Apr 16 nicklas 280   }
3835 11 Apr 16 nicklas 281   
3835 11 Apr 16 nicklas 282   /**
3835 11 Apr 16 nicklas 283     Find an extract for the given location on a bioplates.
3835 11 Apr 16 nicklas 284     @param location The coordinate with one letter for the row and digits for the column
3835 11 Apr 16 nicklas 285   */
3835 11 Apr 16 nicklas 286   protected Extract findExtractByLocation(DbControl dc, BioPlate plate, String location, String fileAndLine)
3835 11 Apr 16 nicklas 287   {
3835 11 Apr 16 nicklas 288     int row = Coordinate.alphaToNumeric(location.substring(0, 1))-1;
3835 11 Apr 16 nicklas 289     int col = Values.getInt(location.substring(1)) - 1;
3835 11 Apr 16 nicklas 290     
3835 11 Apr 16 nicklas 291     ItemQuery<Extract> query = Extract.getQuery();
3835 11 Apr 16 nicklas 292     query.join(Hql.innerJoin("bioWell", "bw"));
3835 11 Apr 16 nicklas 293     query.restrict(Restrictions.eq(Hql.property("bw", "row"), Expressions.integer(row)));
3835 11 Apr 16 nicklas 294     query.restrict(Restrictions.eq(Hql.property("bw", "column"), Expressions.integer(col)));
3835 11 Apr 16 nicklas 295     if (plate != null)
3835 11 Apr 16 nicklas 296     {
3835 11 Apr 16 nicklas 297       query.restrict(Restrictions.eq(Hql.property("bw", "bioPlate"), Expressions.integer(plate.getId())));
3835 11 Apr 16 nicklas 298     }
3835 11 Apr 16 nicklas 299     
3835 11 Apr 16 nicklas 300     List<Extract> list = query.list(dc);
3835 11 Apr 16 nicklas 301     Extract extract = null;
3835 11 Apr 16 nicklas 302     if (list.size() == 0)
3835 11 Apr 16 nicklas 303     {
3835 11 Apr 16 nicklas 304       addErrorMessage(fileAndLine + "Could not find any extract on plate " + 
3835 11 Apr 16 nicklas 305         plate.getName() + "[" + location + "]");
3835 11 Apr 16 nicklas 306     }
3835 11 Apr 16 nicklas 307     else if (list.size() > 1)
3835 11 Apr 16 nicklas 308     {
3835 11 Apr 16 nicklas 309       addErrorMessage(fileAndLine + "Found " + list.size() + " extracts on plate " + 
3835 11 Apr 16 nicklas 310         plate.getName() + "[" + location + "]");
3835 11 Apr 16 nicklas 311     }
3835 11 Apr 16 nicklas 312     else
3835 11 Apr 16 nicklas 313     {
3835 11 Apr 16 nicklas 314       extract = list.get(0);
3835 11 Apr 16 nicklas 315     }
3835 11 Apr 16 nicklas 316     
3835 11 Apr 16 nicklas 317     return extract;
3835 11 Apr 16 nicklas 318   }
3835 11 Apr 16 nicklas 319
3835 11 Apr 16 nicklas 320   
3835 11 Apr 16 nicklas 321   /**
3835 11 Apr 16 nicklas 322     Check that the given extract is located on the same location as in the Caliper
3835 11 Apr 16 nicklas 323     output file.
3835 11 Apr 16 nicklas 324   */
3835 11 Apr 16 nicklas 325   protected boolean checkLocation(DbControl dc, Extract extract, String location, String fileAndLine)
3835 11 Apr 16 nicklas 326   {
3835 11 Apr 16 nicklas 327     int row = Coordinate.alphaToNumeric(location.substring(0, 1))-1;
3835 11 Apr 16 nicklas 328     int col = Values.getInt(location.substring(1)) - 1;
3835 11 Apr 16 nicklas 329     
3835 11 Apr 16 nicklas 330     BioWell well = extract.getBioWell();
3835 11 Apr 16 nicklas 331     
3835 11 Apr 16 nicklas 332     boolean samePosition = row == well.getRow() && col == well.getColumn();
3835 11 Apr 16 nicklas 333     if (!samePosition)
3835 11 Apr 16 nicklas 334     {
3835 11 Apr 16 nicklas 335       addErrorMessage(fileAndLine + "Extract '" + extract.getName() + "' on plate " + 
3835 11 Apr 16 nicklas 336           plate.getName() + " is not on location [" + location + "]");
3835 11 Apr 16 nicklas 337       return false;
3835 11 Apr 16 nicklas 338     }
3835 11 Apr 16 nicklas 339     
3835 11 Apr 16 nicklas 340     return true;
3835 11 Apr 16 nicklas 341   }
3835 11 Apr 16 nicklas 342   
3835 11 Apr 16 nicklas 343 }