extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/cmd/ScanBIdRef.java

Code
Comments
Other
Rev Date Author Line
6342 29 Jun 21 nicklas 1 package net.sf.basedb.reggie.plugins.cmd;
6342 29 Jun 21 nicklas 2
6893 25 Nov 22 nicklas 3 import java.util.Date;
6573 07 Feb 22 nicklas 4 import java.util.List;
6573 07 Feb 22 nicklas 5
6342 29 Jun 21 nicklas 6 import net.sf.basedb.core.DbControl;
6510 03 Dec 21 nicklas 7 import net.sf.basedb.core.PermissionDeniedException;
6581 10 Feb 22 nicklas 8 import net.sf.basedb.core.Sample;
7251 08 Jun 23 nicklas 9 import net.sf.basedb.reggie.Site;
6583 11 Feb 22 nicklas 10 import net.sf.basedb.reggie.dao.Annotationtype;
6510 03 Dec 21 nicklas 11 import net.sf.basedb.reggie.dao.Case;
6573 07 Feb 22 nicklas 12 import net.sf.basedb.reggie.dao.NoSpecimen;
6342 29 Jun 21 nicklas 13 import net.sf.basedb.reggie.dao.Rna;
6342 29 Jun 21 nicklas 14 import net.sf.basedb.reggie.dao.SpecimenTube;
6342 29 Jun 21 nicklas 15
6342 29 Jun 21 nicklas 16 /**
6342 29 Jun 21 nicklas 17   Validator for the SCAN-B ID found in the JSON file. We
6342 29 Jun 21 nicklas 18   support 3 types of references:
6342 29 Jun 21 nicklas 19   
6342 29 Jun 21 nicklas 20   * Prenormalized RNA: A pre-normalized RNA with the exact name should already exist
6342 29 Jun 21 nicklas 21     and it shoult not have existing child items.
6342 29 Jun 21 nicklas 22   * Specimen: An existing specimen with the exact name should already exist.
6510 03 Dec 21 nicklas 23   * Case: A new specimen is created for the given case. The case may or may not already exist.
6583 11 Feb 22 nicklas 24     In this scenario we also support that an existing NoSpecimen item is used and converted
6583 11 Feb 22 nicklas 25     to a specimen item.
6342 29 Jun 21 nicklas 26     
6342 29 Jun 21 nicklas 27   @since 4.32
6342 29 Jun 21 nicklas 28 */
6342 29 Jun 21 nicklas 29 public class ScanBIdRef 
6342 29 Jun 21 nicklas 30   implements ValueValidator<String, ScanBIdRef>
6342 29 Jun 21 nicklas 31 {
6578 09 Feb 22 nicklas 32   private final ImportContext ctx;
6342 29 Jun 21 nicklas 33   
6342 29 Jun 21 nicklas 34   public String id;
7261 16 Jun 23 nicklas 35   public String caseId;
6342 29 Jun 21 nicklas 36   public SampleIdType idType;
6342 29 Jun 21 nicklas 37   public Rna rna;
6342 29 Jun 21 nicklas 38   public SpecimenTube specimen;
6573 07 Feb 22 nicklas 39   public NoSpecimen noSpecimen;
6581 10 Feb 22 nicklas 40   public Sample copyMissingDataFrom;
7229 02 Jun 23 nicklas 41   public SpecimenTube mergeWith;
6510 03 Dec 21 nicklas 42   public Case theCase;
6893 25 Nov 22 nicklas 43   public Date refDate;
6342 29 Jun 21 nicklas 44   
6578 09 Feb 22 nicklas 45   public ScanBIdRef(ImportContext ctx) 
6578 09 Feb 22 nicklas 46   {
6578 09 Feb 22 nicklas 47     this.ctx = ctx;
6578 09 Feb 22 nicklas 48   }
6342 29 Jun 21 nicklas 49   
6342 29 Jun 21 nicklas 50   @Override
6342 29 Jun 21 nicklas 51   public Class<String> getExpectedClass() 
6342 29 Jun 21 nicklas 52   {
6342 29 Jun 21 nicklas 53     return String.class;
6342 29 Jun 21 nicklas 54   }
6342 29 Jun 21 nicklas 55
6342 29 Jun 21 nicklas 56   @Override
6342 29 Jun 21 nicklas 57   public ScanBIdRef isValid(DbControl dc, String value, JsonSection section, String entryKey) 
6342 29 Jun 21 nicklas 58   {
6342 29 Jun 21 nicklas 59     if (value != null)
6342 29 Jun 21 nicklas 60     {
6342 29 Jun 21 nicklas 61       // Convert '-' to '.'
6902 29 Nov 22 nicklas 62       value = value.replace('-', '.').strip();
6342 29 Jun 21 nicklas 63       id = value;
6342 29 Jun 21 nicklas 64       
7234 02 Jun 23 nicklas 65       if (value.matches("\\d{7}(C|D|T)?"))
6342 29 Jun 21 nicklas 66       {
6510 03 Dec 21 nicklas 67         // 7 digits is a SCAN-B CASE ID with optional 'C' or 'D' suffix
6342 29 Jun 21 nicklas 68         idType = SampleIdType.CASE;
7261 16 Jun 23 nicklas 69         caseId = id.substring(0, 7);
7234 02 Jun 23 nicklas 70         // 'T' is for the frozen piece and we should normally not see it
7234 02 Jun 23 nicklas 71         // but if it is here we simple remove it
7261 16 Jun 23 nicklas 72         if (id.endsWith("T")) id = caseId;
6342 29 Jun 21 nicklas 73       }
6342 29 Jun 21 nicklas 74       else if (value.matches("\\d{7}\\.\\d"))
6342 29 Jun 21 nicklas 75       {
6342 29 Jun 21 nicklas 76         // 7 digits + a dot with a single digit
6342 29 Jun 21 nicklas 77         idType = SampleIdType.SPECIMEN;
7261 16 Jun 23 nicklas 78         caseId = id.substring(0, 7);
6342 29 Jun 21 nicklas 79         specimen = SpecimenTube.findByTubeName(dc, id);
6342 29 Jun 21 nicklas 80         if (specimen == null)
6342 29 Jun 21 nicklas 81         {
6342 29 Jun 21 nicklas 82           section.addErrorMessage("Can't find Specimen with name: "+id);
6342 29 Jun 21 nicklas 83         }
6342 29 Jun 21 nicklas 84       }
6342 29 Jun 21 nicklas 85       else if (value.matches("\\d{7}\\..*n.*"))
6342 29 Jun 21 nicklas 86       {
6342 29 Jun 21 nicklas 87         // If we find an 'n' in the name we assume it is a pre-normalized
6342 29 Jun 21 nicklas 88         idType = SampleIdType.PRENORMALISED_RNA;        
7261 16 Jun 23 nicklas 89         caseId = id.substring(0, 7);
6342 29 Jun 21 nicklas 90         rna = Rna.findByName(dc, id, true);
6342 29 Jun 21 nicklas 91         if (rna == null) 
6342 29 Jun 21 nicklas 92         {
6342 29 Jun 21 nicklas 93           section.addErrorMessage("Can't find RNA with name: "+id);
6342 29 Jun 21 nicklas 94         }
6342 29 Jun 21 nicklas 95         else if (!rna.isPreNormalized(dc))
6342 29 Jun 21 nicklas 96         {
6342 29 Jun 21 nicklas 97           section.addWarningMessage("Expected a pre-normalized RNA: "+id);
6342 29 Jun 21 nicklas 98         }
6342 29 Jun 21 nicklas 99         else if (rna.getItem().countExtracts() > 0)
6342 29 Jun 21 nicklas 100         {
6342 29 Jun 21 nicklas 101           section.addErrorMessage("The pre-normalized RNA ("+id+") already have a child library");
6342 29 Jun 21 nicklas 102         }
6342 29 Jun 21 nicklas 103       }
6342 29 Jun 21 nicklas 104       else
6342 29 Jun 21 nicklas 105       {
6342 29 Jun 21 nicklas 106         section.addErrorMessage("Invalid SCANB_ID: " + id);
6342 29 Jun 21 nicklas 107       }
6510 03 Dec 21 nicklas 108       
6510 03 Dec 21 nicklas 109       if (idType != null)
6510 03 Dec 21 nicklas 110       {
7251 08 Jun 23 nicklas 111         // Check that the site prefix is a known site
7251 08 Jun 23 nicklas 112         if (Site.findByCaseName(id) == Site.UNKNOWN)
7251 08 Jun 23 nicklas 113         {
7251 08 Jun 23 nicklas 114           section.addErrorMessage("SCANB_ID doesn't match a known site: " + id);
7251 08 Jun 23 nicklas 115         }
7251 08 Jun 23 nicklas 116         
7251 08 Jun 23 nicklas 117         // Check if a Case already exists (but in most cases it won't)
6510 03 Dec 21 nicklas 118         theCase = Case.findByName(dc, id);
6510 03 Dec 21 nicklas 119         if (theCase != null)
6510 03 Dec 21 nicklas 120         {
6510 03 Dec 21 nicklas 121           try
6510 03 Dec 21 nicklas 122           {
6510 03 Dec 21 nicklas 123             theCase.verifyConsent(dc, null);
6510 03 Dec 21 nicklas 124           }
6510 03 Dec 21 nicklas 125           catch (PermissionDeniedException ex)
6510 03 Dec 21 nicklas 126           {
6510 03 Dec 21 nicklas 127             section.addErrorMessage(ex.getMessage());
6510 03 Dec 21 nicklas 128           }
6510 03 Dec 21 nicklas 129         }
6510 03 Dec 21 nicklas 130       }
6573 07 Feb 22 nicklas 131       
6573 07 Feb 22 nicklas 132       if (idType == SampleIdType.CASE)
6573 07 Feb 22 nicklas 133       {
6573 07 Feb 22 nicklas 134         // Check if we can find an existing NoSpecimen registration that 
6583 11 Feb 22 nicklas 135         // is maybe a placeholder for specimen in this case 
6583 11 Feb 22 nicklas 136         List<NoSpecimen> nsList = NoSpecimen.findByCaseName(dc, id, true);
6583 11 Feb 22 nicklas 137         // We can't use a single NoSpecimen for more than one JSON
6583 11 Feb 22 nicklas 138         for (NoSpecimen ns : nsList)
6578 09 Feb 22 nicklas 139         {
6583 11 Feb 22 nicklas 140           copyMissingDataFrom = ns.getItem();
6583 11 Feb 22 nicklas 141           JsonSection duplicate = null;
6583 11 Feb 22 nicklas 142           String specimenExists = (String)Annotationtype.EXTERNAL_SPECIMEN_EXISTS.getAnnotationValue(dc, ns.getItem());
6583 11 Feb 22 nicklas 143           if ("Yes".equals(specimenExists))
6578 09 Feb 22 nicklas 144           {
6578 09 Feb 22 nicklas 145             if (ctx != null)
6578 09 Feb 22 nicklas 146             {
6578 09 Feb 22 nicklas 147               duplicate = ctx.add("NoSpecimen:"+ns.getName(), section);
6578 09 Feb 22 nicklas 148             }
6578 09 Feb 22 nicklas 149             if (duplicate == null)
6578 09 Feb 22 nicklas 150             {
6578 09 Feb 22 nicklas 151               noSpecimen = ns;
6578 09 Feb 22 nicklas 152               break;
6578 09 Feb 22 nicklas 153             }
6578 09 Feb 22 nicklas 154           }
6578 09 Feb 22 nicklas 155         }
6583 11 Feb 22 nicklas 156         if (noSpecimen == null)
6583 11 Feb 22 nicklas 157         {
6583 11 Feb 22 nicklas 158           // If there is no matching NoSpecimen we try to see if it is possible to use
6583 11 Feb 22 nicklas 159           // another specimen to copy information from. But it must be a specimen
6583 11 Feb 22 nicklas 160           // that has been handled externally.
6583 11 Feb 22 nicklas 161           List<SpecimenTube> spList = SpecimenTube.findByCaseName(dc, id, true);
6583 11 Feb 22 nicklas 162           for (SpecimenTube sp : spList)
6583 11 Feb 22 nicklas 163           {
6583 11 Feb 22 nicklas 164             if (Annotationtype.EXTERNAL_REF.getAnnotationValue(dc, sp.getItem()) != null)
6583 11 Feb 22 nicklas 165             {
6583 11 Feb 22 nicklas 166               copyMissingDataFrom = sp.getItem();
6583 11 Feb 22 nicklas 167             }
6583 11 Feb 22 nicklas 168           }
6583 11 Feb 22 nicklas 169         }
6573 07 Feb 22 nicklas 170       }
6893 25 Nov 22 nicklas 171       // Try to get a sensible reference date that we can compare other dates to
6893 25 Nov 22 nicklas 172       // Dates in the JSON should be after the refDate
6893 25 Nov 22 nicklas 173       if (copyMissingDataFrom != null)
6893 25 Nov 22 nicklas 174       {
6893 25 Nov 22 nicklas 175         refDate = copyMissingDataFrom.getCreationEvent().getEventDate();
6893 25 Nov 22 nicklas 176       }
6342 29 Jun 21 nicklas 177     }
6342 29 Jun 21 nicklas 178     return this;
6342 29 Jun 21 nicklas 179   }
6342 29 Jun 21 nicklas 180
6342 29 Jun 21 nicklas 181   /**
6342 29 Jun 21 nicklas 182     The type of SCAN-B ID.
6342 29 Jun 21 nicklas 183   */
6342 29 Jun 21 nicklas 184   public static enum SampleIdType
6342 29 Jun 21 nicklas 185   {
6342 29 Jun 21 nicklas 186     CASE,
6342 29 Jun 21 nicklas 187     SPECIMEN,
6342 29 Jun 21 nicklas 188     PRENORMALISED_RNA
6342 29 Jun 21 nicklas 189   }
6342 29 Jun 21 nicklas 190
6342 29 Jun 21 nicklas 191 }