extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/release/CohortItem.java

Code
Comments
Other
Rev Date Author Line
3935 13 May 16 nicklas 1 package net.sf.basedb.reggie.plugins.release;
3935 13 May 16 nicklas 2
4444 04 Apr 17 nicklas 3 import java.time.Instant;
4437 31 Mar 17 nicklas 4 import java.time.LocalDateTime;
4437 31 Mar 17 nicklas 5 import java.time.ZoneId;
4437 31 Mar 17 nicklas 6 import java.time.temporal.ChronoUnit;
4472 27 Apr 17 nicklas 7 import java.util.ArrayList;
5098 15 Nov 18 nicklas 8 import java.util.Collections;
4437 31 Mar 17 nicklas 9 import java.util.Date;
5099 15 Nov 18 nicklas 10 import java.util.HashMap;
5549 08 Aug 19 nicklas 11 import java.util.IdentityHashMap;
3936 16 May 16 nicklas 12 import java.util.List;
5099 15 Nov 18 nicklas 13 import java.util.Map;
5099 15 Nov 18 nicklas 14 import java.util.regex.Matcher;
5099 15 Nov 18 nicklas 15 import java.util.regex.Pattern;
3936 16 May 16 nicklas 16
4385 08 Mar 17 nicklas 17 import org.json.simple.JSONArray;
4378 03 Mar 17 nicklas 18 import org.json.simple.JSONObject;
4378 03 Mar 17 nicklas 19
3935 13 May 16 nicklas 20 import net.sf.basedb.core.Annotatable;
4412 21 Mar 17 nicklas 21 import net.sf.basedb.core.AnyToAny;
4412 21 Mar 17 nicklas 22 import net.sf.basedb.core.BasicItem;
5136 22 Nov 18 nicklas 23 import net.sf.basedb.core.BioMaterial;
5089 14 Nov 18 nicklas 24 import net.sf.basedb.core.BioSource;
3935 13 May 16 nicklas 25 import net.sf.basedb.core.DbControl;
5102 16 Nov 18 nicklas 26 import net.sf.basedb.core.DerivedBioAssay;
4607 03 Oct 17 nicklas 27 import net.sf.basedb.core.Extract;
3935 13 May 16 nicklas 28 import net.sf.basedb.core.File;
4385 08 Mar 17 nicklas 29 import net.sf.basedb.core.FileSetMember;
3935 13 May 16 nicklas 30 import net.sf.basedb.core.FileStoreEnabled;
4442 04 Apr 17 nicklas 31 import net.sf.basedb.core.InvalidDataException;
4412 21 Mar 17 nicklas 32 import net.sf.basedb.core.Item;
5234 16 Jan 19 nicklas 33 import net.sf.basedb.core.ItemNotFoundException;
4385 08 Mar 17 nicklas 34 import net.sf.basedb.core.ItemQuery;
5103 16 Nov 18 nicklas 35 import net.sf.basedb.core.RawBioAssay;
4442 04 Apr 17 nicklas 36 import net.sf.basedb.core.Sample;
4437 31 Mar 17 nicklas 37 import net.sf.basedb.core.Type;
4412 21 Mar 17 nicklas 38 import net.sf.basedb.core.query.Expressions;
4412 21 Mar 17 nicklas 39 import net.sf.basedb.core.query.Hql;
7034 10 Feb 23 nicklas 40 import net.sf.basedb.core.query.Orders;
4412 21 Mar 17 nicklas 41 import net.sf.basedb.core.query.Restrictions;
3935 13 May 16 nicklas 42 import net.sf.basedb.core.snapshot.SnapshotManager;
4380 06 Mar 17 nicklas 43 import net.sf.basedb.reggie.converter.ValueConverter;
3936 16 May 16 nicklas 44 import net.sf.basedb.reggie.dao.AlignedSequences;
3935 13 May 16 nicklas 45 import net.sf.basedb.reggie.dao.Annotationtype;
5138 22 Nov 18 nicklas 46 import net.sf.basedb.reggie.dao.Blood;
5142 22 Nov 18 nicklas 47 import net.sf.basedb.reggie.dao.BloodDna;
3940 16 May 16 nicklas 48 import net.sf.basedb.reggie.dao.Case;
3935 13 May 16 nicklas 49 import net.sf.basedb.reggie.dao.Datafiletype;
3958 20 May 16 nicklas 50 import net.sf.basedb.reggie.dao.DemuxedSequences;
5132 21 Nov 18 nicklas 51 import net.sf.basedb.reggie.dao.Dna;
5132 21 Nov 18 nicklas 52 import net.sf.basedb.reggie.dao.FlowThrough;
7007 25 Jan 23 nicklas 53 import net.sf.basedb.reggie.dao.GenotypeCall;
4442 04 Apr 17 nicklas 54 import net.sf.basedb.reggie.dao.Histology;
3937 16 May 16 nicklas 55 import net.sf.basedb.reggie.dao.Library;
3939 16 May 16 nicklas 56 import net.sf.basedb.reggie.dao.Lysate;
3936 16 May 16 nicklas 57 import net.sf.basedb.reggie.dao.MaskedSequences;
3936 16 May 16 nicklas 58 import net.sf.basedb.reggie.dao.MergedSequences;
7006 24 Jan 23 nicklas 59 import net.sf.basedb.reggie.dao.Methylation;
5136 22 Nov 18 nicklas 60 import net.sf.basedb.reggie.dao.NoSpecimen;
3940 16 May 16 nicklas 61 import net.sf.basedb.reggie.dao.Patient;
5549 08 Aug 19 nicklas 62 import net.sf.basedb.reggie.dao.Pipeline;
4472 27 Apr 17 nicklas 63 import net.sf.basedb.reggie.dao.PooledLibrary;
3935 13 May 16 nicklas 64 import net.sf.basedb.reggie.dao.Rawbioassay;
3979 27 May 16 nicklas 65 import net.sf.basedb.reggie.dao.ReggieItem;
3937 16 May 16 nicklas 66 import net.sf.basedb.reggie.dao.Rna;
3937 16 May 16 nicklas 67 import net.sf.basedb.reggie.dao.RnaQc;
4472 27 Apr 17 nicklas 68 import net.sf.basedb.reggie.dao.SequencingRun;
3939 16 May 16 nicklas 69 import net.sf.basedb.reggie.dao.SpecimenTube;
4404 17 Mar 17 nicklas 70 import net.sf.basedb.reggie.json.FilteredJSONObject;
4412 21 Mar 17 nicklas 71 import net.sf.basedb.util.filter.Filter;
4404 17 Mar 17 nicklas 72 import net.sf.basedb.util.filter.NotNullFilter;
4412 21 Mar 17 nicklas 73 import net.sf.basedb.util.filter.StaticFilter;
3935 13 May 16 nicklas 74
3935 13 May 16 nicklas 75 /**
3935 13 May 16 nicklas 76    Represents a single raw bioassay with simple access to all
3935 13 May 16 nicklas 77    of the parent items. To be able to preserve memory and still
3935 13 May 16 nicklas 78    work with multiple raw bioassay items different items may 
3935 13 May 16 nicklas 79    use different DbControl:s and SnapshotManager:s for reading 
3935 13 May 16 nicklas 80    data.
3935 13 May 16 nicklas 81    
3935 13 May 16 nicklas 82    Once an item has been processed by all {@link CohortWriter}:s 
3935 13 May 16 nicklas 83    the used DbControl may be closed and rolled back. Changes
3935 13 May 16 nicklas 84    are never committed.
3935 13 May 16 nicklas 85
3935 13 May 16 nicklas 86   @author nicklas
3935 13 May 16 nicklas 87   @since 4.5
3935 13 May 16 nicklas 88 */
3935 13 May 16 nicklas 89 public class CohortItem 
3935 13 May 16 nicklas 90 {
4442 04 Apr 17 nicklas 91   private final ReleaseExporter exporter;
3935 13 May 16 nicklas 92   private final DbControl dc;
3935 13 May 16 nicklas 93   private final SnapshotManager manager;
5098 15 Nov 18 nicklas 94   private final QueryManager queryManager;
5089 14 Nov 18 nicklas 95   private final BioSource biosource;
5096 14 Nov 18 nicklas 96
5097 15 Nov 18 nicklas 97   private Patient patient;
5096 14 Nov 18 nicklas 98   private List<Case> cases;
5138 22 Nov 18 nicklas 99   private List<Blood> blood;
5142 22 Nov 18 nicklas 100   private List<BloodDna> bloodDna;
5097 15 Nov 18 nicklas 101   private List<SpecimenTube> specimens;
5136 22 Nov 18 nicklas 102   private List<NoSpecimen> noSpecimens;
5099 15 Nov 18 nicklas 103   private List<Lysate> lysates;
5100 15 Nov 18 nicklas 104   private List<Rna> rna;
5132 21 Nov 18 nicklas 105   private List<Dna> dna;
5132 21 Nov 18 nicklas 106   private List<FlowThrough> flowThrough;
5100 15 Nov 18 nicklas 107   private List<RnaQc> rnaQc;
5549 08 Aug 19 nicklas 108   private Map<Pipeline, List<Library>> libraries;
5550 09 Aug 19 nicklas 109   private Map<Pipeline, List<MergedSequences>> mergedSequences;
5103 16 Nov 18 nicklas 110   private List<MaskedSequences> maskedSequences;
5103 16 Nov 18 nicklas 111   private List<AlignedSequences> alignedSequences;
5103 16 Nov 18 nicklas 112   private List<Rawbioassay> stringTieBioAssays;
5103 16 Nov 18 nicklas 113   private List<Rawbioassay> cufflinksBioAssays;
5873 23 Mar 20 nicklas 114   private List<Rawbioassay> variantCallBioAssays;
7006 24 Jan 23 nicklas 115   private List<Methylation> methylationBioAssays;
7007 25 Jan 23 nicklas 116   private List<GenotypeCall> genotypeCalls;
7007 25 Jan 23 nicklas 117   private List<Rawbioassay> oncoArrayBioAssays;
3936 16 May 16 nicklas 118   
5136 22 Nov 18 nicklas 119   private final NameToExternalIdConverter NAME_TO_EXTERNAL_ID;
5136 22 Nov 18 nicklas 120   private final DataFilesFolderToRelaseFolderConverter DATA_FILES_FOLDER_TO_RELEASE_FOLDER;
5103 16 Nov 18 nicklas 121   private final NameToParentDerivedBioAssayConverter TO_PARENT_BIOASSAY_CONVERTER;
4402 17 Mar 17 nicklas 122   
3935 13 May 16 nicklas 123   /**
5096 14 Nov 18 nicklas 124     Create a new cohort item. The biosource is re-loaded with the given DbControl.
5096 14 Nov 18 nicklas 125     @since 4.21
3935 13 May 16 nicklas 126   */
7022 06 Feb 23 nicklas 127   public CohortItem(ReleaseExporter exporter, DbControl dc, SnapshotManager manager, QueryManager queryManager, int biosourceId)
3935 13 May 16 nicklas 128   {
4442 04 Apr 17 nicklas 129     this.exporter = exporter;
3935 13 May 16 nicklas 130     this.dc = dc;
3935 13 May 16 nicklas 131     this.manager = manager;
5098 15 Nov 18 nicklas 132     this.queryManager = queryManager;
5139 22 Nov 18 nicklas 133     this.patient = Patient.getById(dc, biosourceId);
5139 22 Nov 18 nicklas 134     this.biosource = patient.getItem();
5549 08 Aug 19 nicklas 135     this.libraries = new IdentityHashMap<>();
5550 09 Aug 19 nicklas 136     this.mergedSequences = new IdentityHashMap<>();
5103 16 Nov 18 nicklas 137     this.TO_PARENT_BIOASSAY_CONVERTER = new NameToParentDerivedBioAssayConverter();
5136 22 Nov 18 nicklas 138     this.NAME_TO_EXTERNAL_ID = new NameToExternalIdConverter();
5136 22 Nov 18 nicklas 139     this.DATA_FILES_FOLDER_TO_RELEASE_FOLDER = new DataFilesFolderToRelaseFolderConverter(NAME_TO_EXTERNAL_ID);
3935 13 May 16 nicklas 140   }
3935 13 May 16 nicklas 141   
3935 13 May 16 nicklas 142   /**
3935 13 May 16 nicklas 143     Get the DbControl to use for reading data related.
3935 13 May 16 nicklas 144   */
3935 13 May 16 nicklas 145   public DbControl getDbControl()
3935 13 May 16 nicklas 146   {
3935 13 May 16 nicklas 147     return dc;
3935 13 May 16 nicklas 148   }
3935 13 May 16 nicklas 149   
3935 13 May 16 nicklas 150   /**
3935 13 May 16 nicklas 151     Get the snapshot manager to use for reading
3935 13 May 16 nicklas 152     annotation values.
3935 13 May 16 nicklas 153   */
3935 13 May 16 nicklas 154   public SnapshotManager getSnapshotManager()
3935 13 May 16 nicklas 155   {
3935 13 May 16 nicklas 156     return manager;
3935 13 May 16 nicklas 157   }
3935 13 May 16 nicklas 158   
3935 13 May 16 nicklas 159   /**
5198 19 Dec 18 nicklas 160     Get the release exporter.
5198 19 Dec 18 nicklas 161   */
5198 19 Dec 18 nicklas 162   public ReleaseExporter getExporter()
5198 19 Dec 18 nicklas 163   {
5198 19 Dec 18 nicklas 164     return exporter;
5198 19 Dec 18 nicklas 165   }
5198 19 Dec 18 nicklas 166   
5198 19 Dec 18 nicklas 167   /**
5107 19 Nov 18 nicklas 168     Get the name of this cohort item (=the external id of the root biosource)
3935 13 May 16 nicklas 169   */
3935 13 May 16 nicklas 170   public String getName()
3935 13 May 16 nicklas 171   {
5107 19 Nov 18 nicklas 172     return biosource.getExternalId();
3935 13 May 16 nicklas 173   }
3935 13 May 16 nicklas 174   
5099 15 Nov 18 nicklas 175
5099 15 Nov 18 nicklas 176   /**
5099 15 Nov 18 nicklas 177     Replace the SCANB-ID in the string with the external id
5099 15 Nov 18 nicklas 178     creating the "Release ID" of the item.
5099 15 Nov 18 nicklas 179     @since 4.21
5099 15 Nov 18 nicklas 180   */
5099 15 Nov 18 nicklas 181   public String toReleaseId(String nameWithScanBId)
5099 15 Nov 18 nicklas 182   {
5099 15 Nov 18 nicklas 183     return NAME_TO_EXTERNAL_ID.convert(nameWithScanBId);
5099 15 Nov 18 nicklas 184   }
4084 07 Sep 16 nicklas 185   
4084 07 Sep 16 nicklas 186   /**
5106 19 Nov 18 nicklas 187     Replace the SCANB-ID in the string with the external id
5106 19 Nov 18 nicklas 188     and remove the site prefix. For example: 
5106 19 Nov 18 nicklas 189     
5106 19 Nov 18 nicklas 190     /11/1101234.1/l.r.m.c.lib.g/k.a
5106 19 Nov 18 nicklas 191     
5106 19 Nov 18 nicklas 192     is converted to:
5106 19 Nov 18 nicklas 193
5106 19 Nov 18 nicklas 194     /S012345/l.r.m.c.lib.g/k.a
5106 19 Nov 18 nicklas 195     
5106 19 Nov 18 nicklas 196     @since 4.21
5106 19 Nov 18 nicklas 197   */
5106 19 Nov 18 nicklas 198   public String toReleaseFolder(String dataFilesFolder)
5106 19 Nov 18 nicklas 199   {
5106 19 Nov 18 nicklas 200     return DATA_FILES_FOLDER_TO_RELEASE_FOLDER.convert(dataFilesFolder);
5106 19 Nov 18 nicklas 201   }
5106 19 Nov 18 nicklas 202   
3937 16 May 16 nicklas 203
3937 16 May 16 nicklas 204   /**
5098 15 Nov 18 nicklas 205     Get the Patient item.
3940 16 May 16 nicklas 206   */
5098 15 Nov 18 nicklas 207   public Patient getPatient()
3940 16 May 16 nicklas 208   {
5098 15 Nov 18 nicklas 209     return patient;
5096 14 Nov 18 nicklas 210   }
5098 15 Nov 18 nicklas 211
5096 14 Nov 18 nicklas 212   /**
5096 14 Nov 18 nicklas 213     Get all cases that belong to this patient. The cases
5096 14 Nov 18 nicklas 214     must have Consent=Yes and DoNotUse=null.
5096 14 Nov 18 nicklas 215     @since 4.21
5096 14 Nov 18 nicklas 216   */
5096 14 Nov 18 nicklas 217   public List<Case> getCases()
5096 14 Nov 18 nicklas 218   {
5096 14 Nov 18 nicklas 219     if (cases == null)
3940 16 May 16 nicklas 220     {
5098 15 Nov 18 nicklas 221       ItemQuery<Sample> query = queryManager.getCaseQuery(patient);
5098 15 Nov 18 nicklas 222       cases = query == null ? Collections.emptyList() : Case.toList(query.list(dc));
3940 16 May 16 nicklas 223     }
5096 14 Nov 18 nicklas 224     return cases;
3940 16 May 16 nicklas 225   }
5098 15 Nov 18 nicklas 226
3940 16 May 16 nicklas 227   /**
5138 22 Nov 18 nicklas 228     Get all blood sample that belong to this patient. The samples
5138 22 Nov 18 nicklas 229     must have Consent=Yes and DoNotUse=null.
5138 22 Nov 18 nicklas 230     @since 4.21
5138 22 Nov 18 nicklas 231   */
5138 22 Nov 18 nicklas 232   public List<Blood> getBlood()
5138 22 Nov 18 nicklas 233   {
5138 22 Nov 18 nicklas 234     if (blood == null)
5138 22 Nov 18 nicklas 235     {
5138 22 Nov 18 nicklas 236       ItemQuery<Sample> query = queryManager.getBloodQuery(patient);
5138 22 Nov 18 nicklas 237       blood = query == null ? Collections.emptyList() : Blood.toList(query.list(dc));
5142 22 Nov 18 nicklas 238       NAME_TO_EXTERNAL_ID.map(blood);
5138 22 Nov 18 nicklas 239     }
5138 22 Nov 18 nicklas 240     return blood;
5138 22 Nov 18 nicklas 241   }
5138 22 Nov 18 nicklas 242
5138 22 Nov 18 nicklas 243   /**
5142 22 Nov 18 nicklas 244     Get all blood DNA extract that belong to this patient and have
5142 22 Nov 18 nicklas 245     a valid blood parent item. The extracts must have DoNotUse=null.
5142 22 Nov 18 nicklas 246     @since 4.21
5142 22 Nov 18 nicklas 247   */
5142 22 Nov 18 nicklas 248   public List<BloodDna> getBloodDna()
5142 22 Nov 18 nicklas 249   {
5142 22 Nov 18 nicklas 250     if (bloodDna == null)
5142 22 Nov 18 nicklas 251     {
5142 22 Nov 18 nicklas 252       ItemQuery<Extract> query = queryManager.getBloodDnaQuery(getBlood());
5142 22 Nov 18 nicklas 253       bloodDna = query == null ? Collections.emptyList() : BloodDna.toBloodDna(query.list(dc));
5142 22 Nov 18 nicklas 254     }
5142 22 Nov 18 nicklas 255     return bloodDna;
5142 22 Nov 18 nicklas 256   }
5142 22 Nov 18 nicklas 257
5142 22 Nov 18 nicklas 258   /**
5098 15 Nov 18 nicklas 259     Get all specimen that belong to this patient and have a valid Case.
5099 15 Nov 18 nicklas 260     The specimen items must have DoNotUse=null.
5098 15 Nov 18 nicklas 261     @since 4.21
3940 16 May 16 nicklas 262   */
5098 15 Nov 18 nicklas 263   public List<SpecimenTube> getSpecimens()
3940 16 May 16 nicklas 264   {
5098 15 Nov 18 nicklas 265     if (specimens == null)
5098 15 Nov 18 nicklas 266     {
5098 15 Nov 18 nicklas 267       ItemQuery<Sample> query = queryManager.getSpecimenQuery(getCases());
5098 15 Nov 18 nicklas 268       specimens = query == null ? Collections.emptyList() : SpecimenTube.toList(query.list(dc));
5136 22 Nov 18 nicklas 269       NAME_TO_EXTERNAL_ID.map(specimens);
5098 15 Nov 18 nicklas 270     }
5098 15 Nov 18 nicklas 271     return specimens;
3940 16 May 16 nicklas 272   }
3940 16 May 16 nicklas 273
3940 16 May 16 nicklas 274   /**
5139 22 Nov 18 nicklas 275     Get all NoSpecimen items that belong to this patient and have a valid Case.
6580 10 Feb 22 nicklas 276     The items must have DoNotUse=null and ExternalSpecimenExists!=Yes.
5136 22 Nov 18 nicklas 277     @since 4.21
5136 22 Nov 18 nicklas 278   */
5136 22 Nov 18 nicklas 279   public List<NoSpecimen> getNoSpecimens()
5136 22 Nov 18 nicklas 280   {
5136 22 Nov 18 nicklas 281     if (noSpecimens == null)
5136 22 Nov 18 nicklas 282     {
5136 22 Nov 18 nicklas 283       ItemQuery<Sample> query = queryManager.getNoSpecimenQuery(getCases());
5136 22 Nov 18 nicklas 284       noSpecimens = query == null ? Collections.emptyList() : NoSpecimen.toList(query.list(dc));
5136 22 Nov 18 nicklas 285       NAME_TO_EXTERNAL_ID.map(noSpecimens);
5136 22 Nov 18 nicklas 286     }
5136 22 Nov 18 nicklas 287     return noSpecimens;
5136 22 Nov 18 nicklas 288   }
5136 22 Nov 18 nicklas 289
5139 22 Nov 18 nicklas 290   /**
5139 22 Nov 18 nicklas 291     Get the Histology item related to the given specimen. Can be null
5139 22 Nov 18 nicklas 292     if no histology piece was taken. If more than one Histology item 
5139 22 Nov 18 nicklas 293     exists we choose the one that has the latest partition date.
5139 22 Nov 18 nicklas 294     @since 4.21
5139 22 Nov 18 nicklas 295   */
5139 22 Nov 18 nicklas 296   public Histology getHistology(SpecimenTube specimen)
5139 22 Nov 18 nicklas 297   {
5139 22 Nov 18 nicklas 298     ItemQuery<Sample> query = queryManager.getHistologyQuery(specimen);
5139 22 Nov 18 nicklas 299     if (query == null) return null;
5139 22 Nov 18 nicklas 300     
5139 22 Nov 18 nicklas 301     Sample histology = null;
5139 22 Nov 18 nicklas 302     List<Sample> tmp = query.list(dc);
5139 22 Nov 18 nicklas 303     if (tmp.size() > 1)
5139 22 Nov 18 nicklas 304     {
5139 22 Nov 18 nicklas 305       throw new InvalidDataException(
5139 22 Nov 18 nicklas 306         "More than one child histology item was found for specimen '" +
5139 22 Nov 18 nicklas 307           specimen.getName() + "'. This wizard can't be used until that is corrected.");
5139 22 Nov 18 nicklas 308     }
5139 22 Nov 18 nicklas 309     else if (tmp.size() == 1)
5139 22 Nov 18 nicklas 310     {
5139 22 Nov 18 nicklas 311       histology = tmp.get(0);
5139 22 Nov 18 nicklas 312     }
5231 15 Jan 19 nicklas 313     return histology == null ? null : Histology.getById(dc, histology.getId());
5139 22 Nov 18 nicklas 314   }
5136 22 Nov 18 nicklas 315   
5136 22 Nov 18 nicklas 316   /**
5139 22 Nov 18 nicklas 317     Get the GoodStain sample from the related Histology item.
5139 22 Nov 18 nicklas 318     Can be null if no histology piece was taken.
5139 22 Nov 18 nicklas 319   */
5139 22 Nov 18 nicklas 320   public Sample getGoodStainSample(Histology histology)
5139 22 Nov 18 nicklas 321   {
5139 22 Nov 18 nicklas 322     ItemQuery<Sample> query = queryManager.getGoodStainQuery(histology);
5139 22 Nov 18 nicklas 323     if (query == null) return null;
5139 22 Nov 18 nicklas 324   
5139 22 Nov 18 nicklas 325     Sample goodStain = null;
5139 22 Nov 18 nicklas 326     List<Sample> tmp = query.list(dc);
5139 22 Nov 18 nicklas 327     if (tmp.size() > 1)
5139 22 Nov 18 nicklas 328     {
5139 22 Nov 18 nicklas 329       throw new InvalidDataException(
5139 22 Nov 18 nicklas 330         "More than one child sample with GoodStain=TRUE was found for histology '" +
5139 22 Nov 18 nicklas 331           histology.getName() + "'. This wizard can't be used until that is corrected.");
5139 22 Nov 18 nicklas 332     }
5139 22 Nov 18 nicklas 333     else if (tmp.size() == 1)
5139 22 Nov 18 nicklas 334     {
5139 22 Nov 18 nicklas 335       goodStain = tmp.get(0);
5139 22 Nov 18 nicklas 336     }
5139 22 Nov 18 nicklas 337     return goodStain;
5139 22 Nov 18 nicklas 338   }
5139 22 Nov 18 nicklas 339
5139 22 Nov 18 nicklas 340   /**
5099 15 Nov 18 nicklas 341     Get all lysate items that belong to this patient and have a valid Specimen.
5099 15 Nov 18 nicklas 342     The lysate items must have DoNotUse=null.
5099 15 Nov 18 nicklas 343     @since 4.21
5099 15 Nov 18 nicklas 344   */
5099 15 Nov 18 nicklas 345   public List<Lysate> getLysates()
5099 15 Nov 18 nicklas 346   {
5099 15 Nov 18 nicklas 347     if (lysates == null)
5099 15 Nov 18 nicklas 348     {
5099 15 Nov 18 nicklas 349       ItemQuery<Extract> query = queryManager.getLysateQuery(getSpecimens());
5099 15 Nov 18 nicklas 350       lysates = query == null ? Collections.emptyList() : Lysate.toLysate(query.list(dc));
5099 15 Nov 18 nicklas 351     }
5099 15 Nov 18 nicklas 352     return lysates;
5099 15 Nov 18 nicklas 353   }
5100 15 Nov 18 nicklas 354   
5100 15 Nov 18 nicklas 355   /**
5100 15 Nov 18 nicklas 356     Get all RNA items that belong to this patient and have a valid Lysate.
5100 15 Nov 18 nicklas 357     The RNA items must have DoNotUse=null and a RNAQC with either a RIN
5100 15 Nov 18 nicklas 358     or RQS measurement. Note that the RNA in the list returned by this method 
5100 15 Nov 18 nicklas 359     is synchronized with the RNAQC in the list return by {@link #getRnaQc()}.
5100 15 Nov 18 nicklas 360     @since 4.21
5100 15 Nov 18 nicklas 361   */
5100 15 Nov 18 nicklas 362   public List<Rna> getRna()
5100 15 Nov 18 nicklas 363   {
5100 15 Nov 18 nicklas 364     if (rna == null)
5100 15 Nov 18 nicklas 365     {
5100 15 Nov 18 nicklas 366       ItemQuery<Extract> query = queryManager.getRnaQuery(getLysates());
5100 15 Nov 18 nicklas 367       if (query == null)
5100 15 Nov 18 nicklas 368       {
5100 15 Nov 18 nicklas 369         rna = Collections.emptyList();
5100 15 Nov 18 nicklas 370         rnaQc = Collections.emptyList();
5100 15 Nov 18 nicklas 371       }
5100 15 Nov 18 nicklas 372       else
5100 15 Nov 18 nicklas 373       {
5100 15 Nov 18 nicklas 374         List<Extract> tmp = query.list(dc);
5100 15 Nov 18 nicklas 375         rna = new ArrayList<>(tmp.size());
5100 15 Nov 18 nicklas 376         rnaQc = new ArrayList<>(tmp.size());
5100 15 Nov 18 nicklas 377         for (Extract t : tmp)
5100 15 Nov 18 nicklas 378         {
5100 15 Nov 18 nicklas 379           Rna r = Rna.get(t);
5100 15 Nov 18 nicklas 380           RnaQc qc = r.findLastRnaQc(dc, manager);
5100 15 Nov 18 nicklas 381           if (qc != null)
5100 15 Nov 18 nicklas 382           {
5100 15 Nov 18 nicklas 383             rna.add(r);
5100 15 Nov 18 nicklas 384             rnaQc.add(qc);
5100 15 Nov 18 nicklas 385           }
5100 15 Nov 18 nicklas 386         }
5100 15 Nov 18 nicklas 387       }
5100 15 Nov 18 nicklas 388     }
5100 15 Nov 18 nicklas 389     return rna;
5100 15 Nov 18 nicklas 390   }
5131 21 Nov 18 nicklas 391   
5131 21 Nov 18 nicklas 392   /**
5131 21 Nov 18 nicklas 393     Get all DNA items that belong to this patient and have a valid Lysate.
5131 21 Nov 18 nicklas 394     The DNA items must have DoNotUse=null.
5131 21 Nov 18 nicklas 395     @since 4.21
5131 21 Nov 18 nicklas 396   */
5132 21 Nov 18 nicklas 397   public List<Dna> getDna()
5131 21 Nov 18 nicklas 398   {
5131 21 Nov 18 nicklas 399     if (dna == null)
5131 21 Nov 18 nicklas 400     {
5131 21 Nov 18 nicklas 401       ItemQuery<Extract> query = queryManager.getDnaQuery(getLysates());
5132 21 Nov 18 nicklas 402       dna = query == null ? Collections.emptyList() : Dna.toDna(query.list(dc));
5131 21 Nov 18 nicklas 403     }
5131 21 Nov 18 nicklas 404     return dna;
5131 21 Nov 18 nicklas 405   }
5099 15 Nov 18 nicklas 406
5099 15 Nov 18 nicklas 407   /**
5131 21 Nov 18 nicklas 408     Get all FlowThrough items that belong to this patient and have a valid Lysate.
5131 21 Nov 18 nicklas 409     The FlowThrough items must have DoNotUse=null.
5131 21 Nov 18 nicklas 410     @since 4.21
5131 21 Nov 18 nicklas 411   */
5132 21 Nov 18 nicklas 412   public List<FlowThrough> getFlowThrough()
5131 21 Nov 18 nicklas 413   {
5131 21 Nov 18 nicklas 414     if (flowThrough == null)
5131 21 Nov 18 nicklas 415     {
5131 21 Nov 18 nicklas 416       ItemQuery<Extract> query = queryManager.getFlowThroughQuery(getLysates());
5132 21 Nov 18 nicklas 417       flowThrough = query == null ? Collections.emptyList() : FlowThrough.toFlowThrough(query.list(dc));
5131 21 Nov 18 nicklas 418     }
5131 21 Nov 18 nicklas 419     return flowThrough;
5131 21 Nov 18 nicklas 420   }
5131 21 Nov 18 nicklas 421
5131 21 Nov 18 nicklas 422   /**
5100 15 Nov 18 nicklas 423     Get the RNAQC for all RNA items that belong to this patient and have a valid 
5100 15 Nov 18 nicklas 424     Lysate. Note that the RNAQC items returned in this list have corresponding RNA
5100 15 Nov 18 nicklas 425     item returned by {@link #getRna()}.
5100 15 Nov 18 nicklas 426     @since 4.21
5100 15 Nov 18 nicklas 427   */
5100 15 Nov 18 nicklas 428   public List<RnaQc> getRnaQc()
5100 15 Nov 18 nicklas 429   {
5100 15 Nov 18 nicklas 430     if (rnaQc == null) getRna();
5100 15 Nov 18 nicklas 431     return rnaQc;
5100 15 Nov 18 nicklas 432   }
5100 15 Nov 18 nicklas 433   
5100 15 Nov 18 nicklas 434   /**
5549 08 Aug 19 nicklas 435     Get all library items that belong to this patient and have a valid RNA or DNA (depending on
5549 08 Aug 19 nicklas 436     the pipeline). The library items must have a creationDate, DoNotUse=null, a name not ending with '.dil',
5198 19 Dec 18 nicklas 437     be located on a libplate with PlateProcessingResult=Successful and not have a child
5549 08 Aug 19 nicklas 438     alignment on the "Flagged alignments" list (if pipeline=RNA_SEQ).
5549 08 Aug 19 nicklas 439     @since 4.21, 4.23
5101 16 Nov 18 nicklas 440   */
5549 08 Aug 19 nicklas 441   public List<Library> getLibraries(Pipeline pipeline)
5101 16 Nov 18 nicklas 442   {
5549 08 Aug 19 nicklas 443     List<Library> libsInPipeline = libraries.get(pipeline);
5549 08 Aug 19 nicklas 444     if (libsInPipeline == null)
5101 16 Nov 18 nicklas 445     {
5549 08 Aug 19 nicklas 446       ItemQuery<Extract> query = null;
5549 08 Aug 19 nicklas 447       Filter<Extract> filter = null;
5549 08 Aug 19 nicklas 448       if (pipeline == Pipeline.RNA_SEQ)
5549 08 Aug 19 nicklas 449       {
5549 08 Aug 19 nicklas 450         query = queryManager.getLibraryQuery(getRna(), pipeline);
5549 08 Aug 19 nicklas 451         filter = new Filter<Extract>() 
5198 19 Dec 18 nicklas 452           {
5549 08 Aug 19 nicklas 453             @Override
5549 08 Aug 19 nicklas 454             public boolean evaluate(Extract e)
5549 08 Aug 19 nicklas 455             {
5549 08 Aug 19 nicklas 456               return !exporter.hasFlaggedAlignment(e);
5549 08 Aug 19 nicklas 457             }
5549 08 Aug 19 nicklas 458           };
5549 08 Aug 19 nicklas 459       }
5549 08 Aug 19 nicklas 460       else if (pipeline == Pipeline.MIPS)
5549 08 Aug 19 nicklas 461       {
5549 08 Aug 19 nicklas 462         query = queryManager.getLibraryQuery(getDna(), pipeline);
5549 08 Aug 19 nicklas 463         filter = new StaticFilter<>(true);
5549 08 Aug 19 nicklas 464       }
5549 08 Aug 19 nicklas 465       libsInPipeline = query == null ? Collections.emptyList() : Library.toList(query.list(dc), filter);
5549 08 Aug 19 nicklas 466       libraries.put(pipeline, libsInPipeline);
5101 16 Nov 18 nicklas 467     }
5549 08 Aug 19 nicklas 468     return libsInPipeline;
5101 16 Nov 18 nicklas 469   }
5102 16 Nov 18 nicklas 470   
5104 16 Nov 18 nicklas 471   /**
5104 16 Nov 18 nicklas 472     Get all pooled libraries were the given library is included.
5104 16 Nov 18 nicklas 473     No filter is applied on the pooled libraries.
5104 16 Nov 18 nicklas 474     @since 4.21
5104 16 Nov 18 nicklas 475   */
5104 16 Nov 18 nicklas 476   public List<PooledLibrary> getPools(Library library)
5104 16 Nov 18 nicklas 477   {
5104 16 Nov 18 nicklas 478     ItemQuery<Extract> query = queryManager.getPoolQuery(library);
5104 16 Nov 18 nicklas 479     return query == null ? Collections.emptyList() : PooledLibrary.toList(query.list(dc));
5104 16 Nov 18 nicklas 480   }
5104 16 Nov 18 nicklas 481
5104 16 Nov 18 nicklas 482   /**
5104 16 Nov 18 nicklas 483     Get all pooled libraries that are sources to the
5104 16 Nov 18 nicklas 484     given demuxed sequences item.
5104 16 Nov 18 nicklas 485     No filter is applied on the pooled libraries.
5104 16 Nov 18 nicklas 486     @since 4.21
5104 16 Nov 18 nicklas 487   */
5104 16 Nov 18 nicklas 488   public List<PooledLibrary> getPools(DemuxedSequences demux)
5104 16 Nov 18 nicklas 489   {
5104 16 Nov 18 nicklas 490     // TODO -- should we copy this *complex* query to the query manager??
5104 16 Nov 18 nicklas 491     return demux.getPools(dc);
5104 16 Nov 18 nicklas 492   }
5104 16 Nov 18 nicklas 493   
5104 16 Nov 18 nicklas 494   /**
5104 16 Nov 18 nicklas 495     Get all demuxed sequences that are parent items to the given merged sequences item.
5104 16 Nov 18 nicklas 496     No filter is applied to the demuxed sequences.
5104 16 Nov 18 nicklas 497     @since 4.21
5104 16 Nov 18 nicklas 498   */
5104 16 Nov 18 nicklas 499   public List<DemuxedSequences> getDemuxedSequences(MergedSequences merged)
5104 16 Nov 18 nicklas 500   {
5104 16 Nov 18 nicklas 501     ItemQuery<DerivedBioAssay> query = queryManager.getDemuxedSequencesQuery(merged);
5104 16 Nov 18 nicklas 502     return query == null ? Collections.emptyList() : DemuxedSequences.toList(query.list(dc));
5104 16 Nov 18 nicklas 503   }
5104 16 Nov 18 nicklas 504   
5104 16 Nov 18 nicklas 505   /**
5104 16 Nov 18 nicklas 506     Get all sequencing run items that are parent items to the given merged sequences item.
5104 16 Nov 18 nicklas 507     No filter is applied to the sequencing runs.
5104 16 Nov 18 nicklas 508     @since 4.21
5104 16 Nov 18 nicklas 509   */
5104 16 Nov 18 nicklas 510   public List<SequencingRun> getSequencingRuns(MergedSequences merged)
5104 16 Nov 18 nicklas 511   {
5104 16 Nov 18 nicklas 512     ItemQuery<DerivedBioAssay> query = queryManager.getSequencingRunsQuery(merged);
5104 16 Nov 18 nicklas 513     return query == null ? Collections.emptyList() : SequencingRun.toList(query.list(dc));
5104 16 Nov 18 nicklas 514   }
5104 16 Nov 18 nicklas 515   
5104 16 Nov 18 nicklas 516   /**
5104 16 Nov 18 nicklas 517     Get the bioassay that is the parent item to the given child item.
5104 16 Nov 18 nicklas 518     This method can be used to find the parent merged, masked or aligned
5104 16 Nov 18 nicklas 519     sequences from a masked or aligned sequences item or from a raw 
5104 16 Nov 18 nicklas 520     bioassay.
5104 16 Nov 18 nicklas 521   */
5103 16 Nov 18 nicklas 522   public DerivedBioAssay getParentBioAssay(String childName)
5103 16 Nov 18 nicklas 523   {
5103 16 Nov 18 nicklas 524     return TO_PARENT_BIOASSAY_CONVERTER.convert(childName);
5103 16 Nov 18 nicklas 525   }
5103 16 Nov 18 nicklas 526   
5102 16 Nov 18 nicklas 527   /**
5550 09 Aug 19 nicklas 528     Get all merged sequences items for the given pipeline that belong to this patient and 
5550 09 Aug 19 nicklas 529     have a valid library. The merged items must have DoNotUse=null and AnalysisResult=Successful
5550 09 Aug 19 nicklas 530     @since 4.21, 4.23
5102 16 Nov 18 nicklas 531   */
5550 09 Aug 19 nicklas 532   public List<MergedSequences> getMergedSequences(Pipeline pipeline)
5102 16 Nov 18 nicklas 533   {
5550 09 Aug 19 nicklas 534     List<MergedSequences> mergedInPipeline = mergedSequences.get(pipeline);
5550 09 Aug 19 nicklas 535     if (mergedInPipeline == null)
5102 16 Nov 18 nicklas 536     {
5550 09 Aug 19 nicklas 537       ItemQuery<DerivedBioAssay> query = queryManager.getMergedSequencesQuery(getLibraries(pipeline), pipeline);
5550 09 Aug 19 nicklas 538       mergedInPipeline = query == null ? Collections.emptyList() : MergedSequences.toList(query.list(dc));
5550 09 Aug 19 nicklas 539       TO_PARENT_BIOASSAY_CONVERTER.map(mergedInPipeline);
5550 09 Aug 19 nicklas 540       mergedSequences.put(pipeline, mergedInPipeline);
5102 16 Nov 18 nicklas 541     }
5550 09 Aug 19 nicklas 542     return mergedInPipeline;
5102 16 Nov 18 nicklas 543   }
5103 16 Nov 18 nicklas 544   
5103 16 Nov 18 nicklas 545   /**
5103 16 Nov 18 nicklas 546     Get all masked sequences items that belong to this patient and have a valid merged
5103 16 Nov 18 nicklas 547     sequences parent. The masked items must have DoNotUse=null 
5103 16 Nov 18 nicklas 548     (Note! AnalsysisResult is not set on MaskedSequences)
5103 16 Nov 18 nicklas 549     @since 4.21
5103 16 Nov 18 nicklas 550   */
5103 16 Nov 18 nicklas 551   public List<MaskedSequences> getMaskedSequences()
5103 16 Nov 18 nicklas 552   {
5103 16 Nov 18 nicklas 553     if (maskedSequences == null)
5103 16 Nov 18 nicklas 554     {
5550 09 Aug 19 nicklas 555       ItemQuery<DerivedBioAssay> query = queryManager.getMaskedSequencesQuery(getMergedSequences(Pipeline.RNA_SEQ));
5103 16 Nov 18 nicklas 556       maskedSequences = query == null ? Collections.emptyList() : MaskedSequences.toList(query.list(dc));
5103 16 Nov 18 nicklas 557       TO_PARENT_BIOASSAY_CONVERTER.map(maskedSequences);
5103 16 Nov 18 nicklas 558     }
5103 16 Nov 18 nicklas 559     return maskedSequences;
5103 16 Nov 18 nicklas 560   }
5103 16 Nov 18 nicklas 561   
5103 16 Nov 18 nicklas 562   /**
5103 16 Nov 18 nicklas 563     Get all aligned sequences items that belong to this patient and have a valid masked
5103 16 Nov 18 nicklas 564     sequence parents. The aligned items must have DoNotUse=null and AnalysisResult=Successful
5103 16 Nov 18 nicklas 565     @since 4.21
5103 16 Nov 18 nicklas 566   */
5103 16 Nov 18 nicklas 567   public List<AlignedSequences> getAlignedSequences()
5103 16 Nov 18 nicklas 568   {
5103 16 Nov 18 nicklas 569     if (alignedSequences == null)
5103 16 Nov 18 nicklas 570     {
5103 16 Nov 18 nicklas 571       ItemQuery<DerivedBioAssay> query = queryManager.getAlignedSequencesQuery(getMaskedSequences());
5103 16 Nov 18 nicklas 572       alignedSequences = query == null ? Collections.emptyList() : AlignedSequences.toList(query.list(dc));
5103 16 Nov 18 nicklas 573       TO_PARENT_BIOASSAY_CONVERTER.map(alignedSequences);
5103 16 Nov 18 nicklas 574     }
5103 16 Nov 18 nicklas 575     return alignedSequences;
5103 16 Nov 18 nicklas 576   }
5103 16 Nov 18 nicklas 577   
5103 16 Nov 18 nicklas 578   /**
5103 16 Nov 18 nicklas 579     Get all StringTie items that belong to this patient and have a valid aligned
5103 16 Nov 18 nicklas 580     parent. The items must have DoNotUse=null and AnalysisResult=Successful
5103 16 Nov 18 nicklas 581     @since 4.21
5103 16 Nov 18 nicklas 582   */
5103 16 Nov 18 nicklas 583   public List<Rawbioassay> getStringTieBioAssays()
5103 16 Nov 18 nicklas 584   {
5103 16 Nov 18 nicklas 585     if (stringTieBioAssays == null)
5103 16 Nov 18 nicklas 586     {
5103 16 Nov 18 nicklas 587       ItemQuery<RawBioAssay> query = queryManager.getStringTieQuery(getAlignedSequences());
5103 16 Nov 18 nicklas 588       stringTieBioAssays = query == null ? Collections.emptyList() : Rawbioassay.toList(query.list(dc));
5103 16 Nov 18 nicklas 589     }
5103 16 Nov 18 nicklas 590     return stringTieBioAssays;
5103 16 Nov 18 nicklas 591   }
5103 16 Nov 18 nicklas 592   
5103 16 Nov 18 nicklas 593   /**
5103 16 Nov 18 nicklas 594     Get all Cufflinks items that belong to this patient and have a valid aligned
5103 16 Nov 18 nicklas 595     parent. The items must have DoNotUse=null and AnalysisResult=Successful
5103 16 Nov 18 nicklas 596     @since 4.21
5103 16 Nov 18 nicklas 597   */
5103 16 Nov 18 nicklas 598   public List<Rawbioassay> getCufflinksBioAssays()
5103 16 Nov 18 nicklas 599   {
5103 16 Nov 18 nicklas 600     if (cufflinksBioAssays == null)
5103 16 Nov 18 nicklas 601     {
5103 16 Nov 18 nicklas 602       ItemQuery<RawBioAssay> query = queryManager.getCufflinksQuery(getAlignedSequences());
5103 16 Nov 18 nicklas 603       cufflinksBioAssays = query == null ? Collections.emptyList() : Rawbioassay.toList(query.list(dc));
5103 16 Nov 18 nicklas 604     }
5103 16 Nov 18 nicklas 605     return cufflinksBioAssays;
5103 16 Nov 18 nicklas 606   }
5101 16 Nov 18 nicklas 607
5873 23 Mar 20 nicklas 608   /**
5873 23 Mar 20 nicklas 609     Get all VariantCall items that belong to this patient and have a valid aligned
5873 23 Mar 20 nicklas 610     parent. The items must have DoNotUse=null and AnalysisResult=Successful
5873 23 Mar 20 nicklas 611     @since 4.26
5873 23 Mar 20 nicklas 612   */
5873 23 Mar 20 nicklas 613   public List<Rawbioassay> getVariantCallBioAssays()
5873 23 Mar 20 nicklas 614   {
5873 23 Mar 20 nicklas 615     if (variantCallBioAssays == null)
5873 23 Mar 20 nicklas 616     {
5873 23 Mar 20 nicklas 617       ItemQuery<RawBioAssay> query = queryManager.getVariantCallQuery(getAlignedSequences());
5873 23 Mar 20 nicklas 618       variantCallBioAssays = query == null ? Collections.emptyList() : Rawbioassay.toList(query.list(dc));
5873 23 Mar 20 nicklas 619     }
5873 23 Mar 20 nicklas 620     return variantCallBioAssays;
5873 23 Mar 20 nicklas 621   }
5873 23 Mar 20 nicklas 622
3979 27 May 16 nicklas 623   /**
7006 24 Jan 23 nicklas 624     Get all Methylations items that belong to this patient. The items must have 
7006 24 Jan 23 nicklas 625     DoNotUse=null and AnalysisResult=Successful
7006 24 Jan 23 nicklas 626     @since 4.44
7006 24 Jan 23 nicklas 627   */
7006 24 Jan 23 nicklas 628   public List<Methylation> getMethylationBioAssays()
7006 24 Jan 23 nicklas 629   {
7006 24 Jan 23 nicklas 630     if (methylationBioAssays == null)
7006 24 Jan 23 nicklas 631     {
7006 24 Jan 23 nicklas 632       ItemQuery<DerivedBioAssay> query = queryManager.getMethylationQuery(getDna());
7006 24 Jan 23 nicklas 633       methylationBioAssays = query == null ? Collections.emptyList() : Methylation.toList(query.list(dc));
7006 24 Jan 23 nicklas 634     }
7006 24 Jan 23 nicklas 635     return methylationBioAssays;
7006 24 Jan 23 nicklas 636   }
7006 24 Jan 23 nicklas 637
7006 24 Jan 23 nicklas 638   /**
7007 25 Jan 23 nicklas 639     Get all GenotypeCall items that belong to this patient. The items must have 
7007 25 Jan 23 nicklas 640     DoNotUse=null and AnalysisResult=Successful
7007 25 Jan 23 nicklas 641     @since 4.44
7007 25 Jan 23 nicklas 642   */
7007 25 Jan 23 nicklas 643   public List<GenotypeCall> getGenotypeCalls()
7007 25 Jan 23 nicklas 644   {
7007 25 Jan 23 nicklas 645     if (genotypeCalls == null)
7007 25 Jan 23 nicklas 646     {
7007 25 Jan 23 nicklas 647       ItemQuery<DerivedBioAssay> query = queryManager.getGenotypeCallsQuery(getBloodDna());
7007 25 Jan 23 nicklas 648       genotypeCalls = query == null ? Collections.emptyList() : GenotypeCall.toList(query.list(dc));
7007 25 Jan 23 nicklas 649       TO_PARENT_BIOASSAY_CONVERTER.map(genotypeCalls);
7007 25 Jan 23 nicklas 650     }
7007 25 Jan 23 nicklas 651     return genotypeCalls;
7007 25 Jan 23 nicklas 652   }
7007 25 Jan 23 nicklas 653   
7007 25 Jan 23 nicklas 654   /**
7007 25 Jan 23 nicklas 655     Get all OncoArray items that belong to this patient and have a valid genotype 
7007 25 Jan 23 nicklas 656     call parent. The items must have DoNotUse=null and AnalysisResult=Successful
7007 25 Jan 23 nicklas 657     @since 4.44
7007 25 Jan 23 nicklas 658   */
7007 25 Jan 23 nicklas 659   public List<Rawbioassay> getOncoArrayBioAssays()
7007 25 Jan 23 nicklas 660   {
7007 25 Jan 23 nicklas 661     if (oncoArrayBioAssays == null)
7007 25 Jan 23 nicklas 662     {
7007 25 Jan 23 nicklas 663       ItemQuery<RawBioAssay> query = queryManager.getOncoArrayQuery(getGenotypeCalls());
7007 25 Jan 23 nicklas 664       oncoArrayBioAssays = query == null ? Collections.emptyList() : Rawbioassay.toList(query.list(dc));
7007 25 Jan 23 nicklas 665     }
7007 25 Jan 23 nicklas 666     return oncoArrayBioAssays;
7007 25 Jan 23 nicklas 667   }
7007 25 Jan 23 nicklas 668   
7007 25 Jan 23 nicklas 669   /**
3935 13 May 16 nicklas 670     Helper method for calling 
3935 13 May 16 nicklas 671     {@link Annotationtype#getAnnotationValue(DbControl, SnapshotManager, Annotatable)}
3935 13 May 16 nicklas 672   */
3935 13 May 16 nicklas 673   public Object getAnnotationValue(Annotationtype at, Annotatable item)
3935 13 May 16 nicklas 674   {
7010 25 Jan 23 nicklas 675     return item == null ? null : at.getAnnotationValue(dc, manager, item);
3935 13 May 16 nicklas 676   }
7010 25 Jan 23 nicklas 677
7010 25 Jan 23 nicklas 678   /**
7010 25 Jan 23 nicklas 679     Helper method for calling 
7010 25 Jan 23 nicklas 680     {@link Annotationtype#getAnnotationValue(DbControl, SnapshotManager, Annotatable)}
7010 25 Jan 23 nicklas 681     @since 4.44
7010 25 Jan 23 nicklas 682   */
7010 25 Jan 23 nicklas 683   public Object getAnnotationValue(Annotationtype at, ReggieItem<?> item)
7010 25 Jan 23 nicklas 684   {
7010 25 Jan 23 nicklas 685     return item == null ? null : at.getAnnotationValue(dc, manager, item.getItem());
7010 25 Jan 23 nicklas 686   }
3935 13 May 16 nicklas 687   
3935 13 May 16 nicklas 688   /**
4437 31 Mar 17 nicklas 689     Helper method for for date and timestamp annotations that return LocalDateTime
4437 31 Mar 17 nicklas 690     objects instead of Date (Useful when there is need to compare or calculate time difference
4437 31 Mar 17 nicklas 691     between dates/time). DATE annotations are truncated to whole days.
4437 31 Mar 17 nicklas 692     {@link Annotationtype#getAnnotationValue(DbControl, SnapshotManager, Annotatable)}
4437 31 Mar 17 nicklas 693     @since 4.10
4437 31 Mar 17 nicklas 694   */
4437 31 Mar 17 nicklas 695   public LocalDateTime getDateTimeAnnotation(Annotationtype at, Annotatable item)
4437 31 Mar 17 nicklas 696   {
4437 31 Mar 17 nicklas 697     Date date = (Date)at.getAnnotationValue(dc, manager, item);
4437 31 Mar 17 nicklas 698     if (date == null) return null;
4444 04 Apr 17 nicklas 699     // IMPORTANT! We must use Instant.ofEpochMilli() instead of Date.toInstant() 
4444 04 Apr 17 nicklas 700     // since java.sql.Date.toInstant() throw UnsupporterOperationException
4444 04 Apr 17 nicklas 701     LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
4437 31 Mar 17 nicklas 702     return (at.getValueType() == Type.TIMESTAMP) ? dateTime : dateTime.truncatedTo(ChronoUnit.DAYS);
4437 31 Mar 17 nicklas 703   }
4437 31 Mar 17 nicklas 704   
4437 31 Mar 17 nicklas 705   /**
4378 03 Mar 17 nicklas 706     Get an annotation value as a JSON object with
4378 03 Mar 17 nicklas 707     two fields: 
4378 03 Mar 17 nicklas 708     name: name of the annotation type,
4378 03 Mar 17 nicklas 709     value: The annotation value
6777 17 Jun 22 nicklas 710     The "value" field is not included if the annotation value is null
4378 03 Mar 17 nicklas 711     @since 4.10
4378 03 Mar 17 nicklas 712   */
4380 06 Mar 17 nicklas 713   @SuppressWarnings({ "rawtypes", "unchecked" })
4474 27 Apr 17 nicklas 714   public JSONObject getAnnotationJSON(Annotationtype at, Annotatable item, ValueConverter converter)
4378 03 Mar 17 nicklas 715   {
4378 03 Mar 17 nicklas 716     Object value = getAnnotationValue(at, item);
4380 06 Mar 17 nicklas 717     if (converter != null) value = converter.convert(value);
4378 03 Mar 17 nicklas 718     return createAnnotationJSON(at.getName(), value);
4378 03 Mar 17 nicklas 719   }
7010 25 Jan 23 nicklas 720   /**
7010 25 Jan 23 nicklas 721     Get an annotation value as a JSON object with
7010 25 Jan 23 nicklas 722     two fields: 
7010 25 Jan 23 nicklas 723     name: name of the annotation type,
7010 25 Jan 23 nicklas 724     value: The annotation value
7010 25 Jan 23 nicklas 725     The "value" field is not included if the annotation value is null
7010 25 Jan 23 nicklas 726     @since 4.44
7010 25 Jan 23 nicklas 727   */
7010 25 Jan 23 nicklas 728   @SuppressWarnings({ "rawtypes", "unchecked" })
7010 25 Jan 23 nicklas 729   public JSONObject getAnnotationJSON(Annotationtype at, ReggieItem<?> item, ValueConverter converter)
7010 25 Jan 23 nicklas 730   {
7010 25 Jan 23 nicklas 731     Object value = getAnnotationValue(at, item);
7010 25 Jan 23 nicklas 732     if (converter != null) value = converter.convert(value);
7010 25 Jan 23 nicklas 733     return createAnnotationJSON(at.getName(), value);
7010 25 Jan 23 nicklas 734   }
4378 03 Mar 17 nicklas 735   
5142 22 Nov 18 nicklas 736   public JSONArray getDataFilesJSON(Datafiletype dft, FileStoreEnabled item, Filter<File> filter, boolean translateFilenames)
4385 08 Mar 17 nicklas 737   {
4385 08 Mar 17 nicklas 738     JSONArray jsonFiles = new JSONArray();
4601 29 Sep 17 nicklas 739     if (item.hasFileSet())
4385 08 Mar 17 nicklas 740     {
4601 29 Sep 17 nicklas 741       ItemQuery<FileSetMember> query = item.getFileSet().getMembers(dft.get(dc));
4601 29 Sep 17 nicklas 742       if (filter == null) filter = new StaticFilter<>(true);
4601 29 Sep 17 nicklas 743       for (FileSetMember mbr : query.list(dc))
4438 31 Mar 17 nicklas 744       {
4601 29 Sep 17 nicklas 745         File f = mbr.getFile();
4601 29 Sep 17 nicklas 746         if (filter.evaluate(f))
4601 29 Sep 17 nicklas 747         {
5142 22 Nov 18 nicklas 748           String filename = f.getName();
4601 29 Sep 17 nicklas 749           JSONObject jsonFile = new FilteredJSONObject(new NotNullFilter<>(false));
4601 29 Sep 17 nicklas 750           jsonFile.put("type", dft.getName());
5142 22 Nov 18 nicklas 751           jsonFile.put("originalName", filename);
5142 22 Nov 18 nicklas 752           jsonFile.put("name", translateFilenames ? toReleaseId(filename) : filename);
4601 29 Sep 17 nicklas 753           jsonFile.put("size", f.getSize());
4601 29 Sep 17 nicklas 754           jsonFile.put("mimeType", f.getMimeType());
4601 29 Sep 17 nicklas 755           jsonFile.put("characterSet", f.getCharacterSet());
4601 29 Sep 17 nicklas 756           jsonFiles.add(jsonFile);
4601 29 Sep 17 nicklas 757         }
4438 31 Mar 17 nicklas 758       }
4385 08 Mar 17 nicklas 759     }
4385 08 Mar 17 nicklas 760     return jsonFiles;
4385 08 Mar 17 nicklas 761   }
4385 08 Mar 17 nicklas 762   
5142 22 Nov 18 nicklas 763   public JSONArray getLinkedFilesJSON(BasicItem item, Filter<File> filter, boolean translateFilenames)
4412 21 Mar 17 nicklas 764   {
4412 21 Mar 17 nicklas 765     ItemQuery<AnyToAny> fileQuery = AnyToAny.getLinksFrom(item);
4412 21 Mar 17 nicklas 766     fileQuery.restrict(Restrictions.eq(Hql.property("toType"), Expressions.integer(Item.FILE.getValue())));
7034 10 Feb 23 nicklas 767     // Sorting is not critical but makes it easer to compare results
7034 10 Feb 23 nicklas 768     if (exporter.getOptions().debugMode())
7034 10 Feb 23 nicklas 769     {
7034 10 Feb 23 nicklas 770       fileQuery.order(Orders.asc(Hql.property("name")));
7034 10 Feb 23 nicklas 771     }
4412 21 Mar 17 nicklas 772     JSONArray jsonFiles = new JSONArray();
4412 21 Mar 17 nicklas 773     if (filter == null) filter = new StaticFilter<>(true);
4412 21 Mar 17 nicklas 774     for (AnyToAny any : fileQuery.list(dc))
4412 21 Mar 17 nicklas 775     {
4412 21 Mar 17 nicklas 776       File f = (File)any.getTo();
4412 21 Mar 17 nicklas 777       if (filter.evaluate(f))
4412 21 Mar 17 nicklas 778       {
5142 22 Nov 18 nicklas 779         String filename = f.getName();
4412 21 Mar 17 nicklas 780         JSONObject jsonFile = new FilteredJSONObject(new NotNullFilter<>(false));
4412 21 Mar 17 nicklas 781         jsonFile.put("link", any.getName());
5142 22 Nov 18 nicklas 782         jsonFile.put("originalName", filename);
5142 22 Nov 18 nicklas 783         jsonFile.put("name", translateFilenames ? toReleaseId(filename) : filename);
4412 21 Mar 17 nicklas 784         jsonFile.put("size", f.getSize());
4412 21 Mar 17 nicklas 785         jsonFile.put("mimeType", f.getMimeType());
4412 21 Mar 17 nicklas 786         jsonFile.put("characterSet", f.getCharacterSet());
4412 21 Mar 17 nicklas 787         jsonFiles.add(jsonFile);
4412 21 Mar 17 nicklas 788       }
4412 21 Mar 17 nicklas 789     }
4412 21 Mar 17 nicklas 790     return jsonFiles;
4412 21 Mar 17 nicklas 791   }
4412 21 Mar 17 nicklas 792   
4378 03 Mar 17 nicklas 793   /**
4378 03 Mar 17 nicklas 794     Create an annotation JSON object with
4378 03 Mar 17 nicklas 795     two fields: 
4378 03 Mar 17 nicklas 796     name: name of the annotation type,
4378 03 Mar 17 nicklas 797     value: The annotation value
6777 17 Jun 22 nicklas 798     The "value" field is only included for non-null values.
4378 03 Mar 17 nicklas 799     @since 4.10
4378 03 Mar 17 nicklas 800   */
4378 03 Mar 17 nicklas 801   public JSONObject createAnnotationJSON(String name, Object value)
4378 03 Mar 17 nicklas 802   {
6777 17 Jun 22 nicklas 803     JSONObject json = new JSONObject();
6777 17 Jun 22 nicklas 804     json.put("name", name);
6777 17 Jun 22 nicklas 805     if (value != null) json.put("value", value);
4378 03 Mar 17 nicklas 806     return json;
4378 03 Mar 17 nicklas 807   }
4378 03 Mar 17 nicklas 808   
4378 03 Mar 17 nicklas 809   /**
4466 25 Apr 17 nicklas 810     Creates an annotation that should be imported as a "batch index"
4466 25 Apr 17 nicklas 811     on the other side. Since we can't load all items and sort them here
4466 25 Apr 17 nicklas 812     to find the "index" we convert the "value" to a unique string (not 
4466 25 Apr 17 nicklas 813     related the "value") that is exported as a proxy for the value. Once all 
4466 25 Apr 17 nicklas 814     items has been exported we can sort the proxies and generate a mapping file 
4466 25 Apr 17 nicklas 815     for each "proxy"->"index". When importing the importer need to lookup the index 
4466 25 Apr 17 nicklas 816     in the mapping file.
4466 25 Apr 17 nicklas 817     
4466 25 Apr 17 nicklas 818     @param name The batch name, typically the same name as an exported 
4466 25 Apr 17 nicklas 819       annotation type (this will be automatically picked up by the importer)
4466 25 Apr 17 nicklas 820     @param value The "batch" value, typically a date or some other value that
4466 25 Apr 17 nicklas 821       identifies the batch. By sorting all the unique values we get the "index"
4466 25 Apr 17 nicklas 822       that is going to be imported.
4466 25 Apr 17 nicklas 823   */
4466 25 Apr 17 nicklas 824   public JSONObject createBatchIndexAnnotationJSON(String name, String value)
4466 25 Apr 17 nicklas 825   {
4470 26 Apr 17 nicklas 826     if (value == null) return null;
4466 25 Apr 17 nicklas 827     String proxy = exporter.getBatchIndexProxy(name, value);
4466 25 Apr 17 nicklas 828     return createAnnotationJSON(name, proxy);
4466 25 Apr 17 nicklas 829   }
4466 25 Apr 17 nicklas 830   
3935 13 May 16 nicklas 831
5106 19 Nov 18 nicklas 832   /**
5106 19 Nov 18 nicklas 833     Converts a name that starts with a SCAN-B id to a name where
5106 19 Nov 18 nicklas 834     the SCAN-B id has been replaced with a release id.
5106 19 Nov 18 nicklas 835   */
5106 19 Nov 18 nicklas 836   static class NameToExternalIdConverter
4402 17 Mar 17 nicklas 837     implements ValueConverter<String, String>
4402 17 Mar 17 nicklas 838   {
4402 17 Mar 17 nicklas 839
5099 15 Nov 18 nicklas 840     private final Pattern specimenNamePattern;
5099 15 Nov 18 nicklas 841     private final Map<String, String> nameToExternalId;
5136 22 Nov 18 nicklas 842     NameToExternalIdConverter()
5099 15 Nov 18 nicklas 843     {
5142 22 Nov 18 nicklas 844       this.specimenNamePattern = Pattern.compile("(\\d{7}\\.\\w+)(.*)");
5099 15 Nov 18 nicklas 845       this.nameToExternalId = new HashMap<>();
5136 22 Nov 18 nicklas 846     }
5136 22 Nov 18 nicklas 847     
5136 22 Nov 18 nicklas 848     void map(List<? extends ReggieItem<? extends BioMaterial>> items)
5136 22 Nov 18 nicklas 849     {
5136 22 Nov 18 nicklas 850       for (ReggieItem<? extends BioMaterial> item : items)
5099 15 Nov 18 nicklas 851       {
5136 22 Nov 18 nicklas 852         nameToExternalId.put(item.getName(), item.getItem().getExternalId());
5099 15 Nov 18 nicklas 853       }
5099 15 Nov 18 nicklas 854     }
5099 15 Nov 18 nicklas 855     
4402 17 Mar 17 nicklas 856     @Override
5099 15 Nov 18 nicklas 857     public String convert(String nameWithScanBId) 
4402 17 Mar 17 nicklas 858     {
5099 15 Nov 18 nicklas 859       Matcher m = specimenNamePattern.matcher(nameWithScanBId);
5099 15 Nov 18 nicklas 860       if (m.matches())
5099 15 Nov 18 nicklas 861       {
5099 15 Nov 18 nicklas 862         String spName = m.group(1);
5099 15 Nov 18 nicklas 863         String externalId = nameToExternalId.get(spName);
5136 22 Nov 18 nicklas 864         if (externalId == null) 
5136 22 Nov 18 nicklas 865         {
5142 22 Nov 18 nicklas 866           throw new InvalidDataException("Could not find ReleaseID for: " + spName + " (" + nameWithScanBId + ")");
5136 22 Nov 18 nicklas 867         }
5099 15 Nov 18 nicklas 868         return externalId + m.group(2);
5099 15 Nov 18 nicklas 869       }
5142 22 Nov 18 nicklas 870       throw new InvalidDataException("Can't convert name to ReleaseID since it doesn't match expected pattern for SCAN-B specimen: " + nameWithScanBId);
4402 17 Mar 17 nicklas 871     }
4402 17 Mar 17 nicklas 872   }
4422 24 Mar 17 nicklas 873   
5104 16 Nov 18 nicklas 874   /**
5106 19 Nov 18 nicklas 875     Converts a DataFilesFolder annotation value with a SCAN-B id in the path
5106 19 Nov 18 nicklas 876     to a path that is using the release ID instead.
5106 19 Nov 18 nicklas 877   */
5106 19 Nov 18 nicklas 878   static class DataFilesFolderToRelaseFolderConverter
5106 19 Nov 18 nicklas 879     implements ValueConverter<String, String>
5106 19 Nov 18 nicklas 880   {
5106 19 Nov 18 nicklas 881     
5106 19 Nov 18 nicklas 882     private final ValueConverter<String, String> nameToReleaseId;
5106 19 Nov 18 nicklas 883     DataFilesFolderToRelaseFolderConverter(ValueConverter<String, String> nameToRelaseId)
5106 19 Nov 18 nicklas 884     {
5106 19 Nov 18 nicklas 885       this.nameToReleaseId = nameToRelaseId;
5106 19 Nov 18 nicklas 886     }
5106 19 Nov 18 nicklas 887     
5106 19 Nov 18 nicklas 888     @Override
5106 19 Nov 18 nicklas 889     public String convert(String value) 
5106 19 Nov 18 nicklas 890     {
5550 09 Aug 19 nicklas 891       // If the path starts with /debug we remove that
5550 09 Aug 19 nicklas 892       if (value.startsWith("/debug/")) value = value.substring(6);
5106 19 Nov 18 nicklas 893       // If the path starts with a two-digit directory (eg. /11/) we remove the first 4 characters
5106 19 Nov 18 nicklas 894       if (value.matches("/\\d\\d/.*")) value = value.substring(4);
5106 19 Nov 18 nicklas 895       value = "/" + nameToReleaseId.convert(value);
5106 19 Nov 18 nicklas 896       return value;
5106 19 Nov 18 nicklas 897     }
5106 19 Nov 18 nicklas 898   }
5106 19 Nov 18 nicklas 899
5106 19 Nov 18 nicklas 900   
5106 19 Nov 18 nicklas 901   /**
5104 16 Nov 18 nicklas 902     Use for caching loaded some derived bioassay types (merged, masked, aligned)
5104 16 Nov 18 nicklas 903     to make it easier to lookup parent items by name.
5104 16 Nov 18 nicklas 904     A child item name is given which is truncated at the last '.' which gives
5104 16 Nov 18 nicklas 905     us the name of the parent which is lookup up in this cache.
5104 16 Nov 18 nicklas 906   */
5103 16 Nov 18 nicklas 907   class NameToParentDerivedBioAssayConverter
5103 16 Nov 18 nicklas 908     implements ValueConverter<String, DerivedBioAssay>
5103 16 Nov 18 nicklas 909   {
5103 16 Nov 18 nicklas 910     private final Map<String, DerivedBioAssay> allItems;
5103 16 Nov 18 nicklas 911     
5103 16 Nov 18 nicklas 912     NameToParentDerivedBioAssayConverter()
5103 16 Nov 18 nicklas 913     {
5103 16 Nov 18 nicklas 914       this.allItems = new HashMap<>();
5103 16 Nov 18 nicklas 915     }
5103 16 Nov 18 nicklas 916     
5103 16 Nov 18 nicklas 917     void map(List<? extends ReggieItem<DerivedBioAssay>> items)
5103 16 Nov 18 nicklas 918     {
5103 16 Nov 18 nicklas 919       if (items == null || items.size() == 0) return;
5103 16 Nov 18 nicklas 920       for (ReggieItem<? extends DerivedBioAssay> r : items)
5103 16 Nov 18 nicklas 921       {
5103 16 Nov 18 nicklas 922         allItems.put(r.getName(), r.getItem());
5103 16 Nov 18 nicklas 923       }
5103 16 Nov 18 nicklas 924     }
5103 16 Nov 18 nicklas 925     
5103 16 Nov 18 nicklas 926     @Override
5103 16 Nov 18 nicklas 927     public DerivedBioAssay convert(String nameOfChild) 
5103 16 Nov 18 nicklas 928     {
5104 16 Nov 18 nicklas 929       // Get the name of the parent by removing the part after the last '.'
5103 16 Nov 18 nicklas 930       String nameOfParent = nameOfChild.substring(0, nameOfChild.lastIndexOf('.'));
5234 16 Jan 19 nicklas 931       DerivedBioAssay parent = allItems.get(nameOfParent);
5234 16 Jan 19 nicklas 932       if (parent == null)
5234 16 Jan 19 nicklas 933       {
5234 16 Jan 19 nicklas 934         // This should *NOT* happen! If it does something is incorrectly linked or manually renamed
5234 16 Jan 19 nicklas 935         throw new ItemNotFoundException("Could not find parent of '" + nameOfChild + "' with name: " + nameOfParent);
5234 16 Jan 19 nicklas 936       }
5234 16 Jan 19 nicklas 937       return parent;
5103 16 Nov 18 nicklas 938     }
5103 16 Nov 18 nicklas 939   }
5103 16 Nov 18 nicklas 940   
4567 01 Sep 17 nicklas 941   
3935 13 May 16 nicklas 942 }