extensions/net.sf.basedb.meludi/trunk/src/net/sf/basedb/meludi/dao/Blood.java

Code
Comments
Other
Rev Date Author Line
4795 08 May 18 olle 1 package net.sf.basedb.meludi.dao;
4795 08 May 18 olle 2
4795 08 May 18 olle 3 import java.util.ArrayList;
4795 08 May 18 olle 4 import java.util.List;
4795 08 May 18 olle 5
4831 05 Jun 18 olle 6 import org.json.simple.JSONObject;
4831 05 Jun 18 olle 7
5468 04 Jun 19 olle 8 import net.sf.basedb.core.AnnotationRestriction;
4795 08 May 18 olle 9 import net.sf.basedb.core.AnnotationSimpleRestriction;
4899 10 Jul 18 olle 10 import net.sf.basedb.core.AnnotationType;
4795 08 May 18 olle 11 import net.sf.basedb.core.DbControl;
4795 08 May 18 olle 12 import net.sf.basedb.core.Include;
4795 08 May 18 olle 13 import net.sf.basedb.core.InvalidDataException;
4795 08 May 18 olle 14 import net.sf.basedb.core.ItemQuery;
4795 08 May 18 olle 15 import net.sf.basedb.core.Operator;
4795 08 May 18 olle 16 import net.sf.basedb.core.PermissionDeniedException;
4795 08 May 18 olle 17 import net.sf.basedb.core.Sample;
4868 25 Jun 18 olle 18 import net.sf.basedb.core.SessionControl;
4795 08 May 18 olle 19 import net.sf.basedb.core.Type;
4795 08 May 18 olle 20 import net.sf.basedb.core.query.Annotations;
4795 08 May 18 olle 21 import net.sf.basedb.core.query.Expressions;
4795 08 May 18 olle 22 import net.sf.basedb.core.query.Hql;
4795 08 May 18 olle 23 import net.sf.basedb.core.query.Orders;
4795 08 May 18 olle 24 import net.sf.basedb.core.query.Restrictions;
4831 05 Jun 18 olle 25 import net.sf.basedb.meludi.JsonUtil;
4795 08 May 18 olle 26 import net.sf.basedb.meludi.Meludi;
4795 08 May 18 olle 27 import net.sf.basedb.meludi.ReservedItems;
4795 08 May 18 olle 28 import net.sf.basedb.util.MD5;
4795 08 May 18 olle 29 import net.sf.basedb.util.Values;
4795 08 May 18 olle 30
4795 08 May 18 olle 31 /**
4795 08 May 18 olle 32   Class for loading information that is related to blood referral forms.
4795 08 May 18 olle 33   
4795 08 May 18 olle 34   @author nicklas
4795 08 May 18 olle 35   @since 2.2
4795 08 May 18 olle 36 */
4795 08 May 18 olle 37 public class Blood
4795 08 May 18 olle 38   extends MeludiItem<Sample>
4795 08 May 18 olle 39 {
4795 08 May 18 olle 40
4795 08 May 18 olle 41   /**
4795 08 May 18 olle 42     Find blood information by case name. This method will check for 
4795 08 May 18 olle 43     {@link Subtype#BLOOD} samples with a name matching the case name (eg. xxx.b)
4795 08 May 18 olle 44     If useBlodSampleAnnotation is set the lookup will use the 'BloodSample' annotation
4795 08 May 18 olle 45     when searching for samples. If the case name has a suffix 'C' only samples annotated 
4795 08 May 18 olle 46     with BloodSample=PreNeo are considered. If no suffix is specified PreNeo samples 
4795 08 May 18 olle 47     are ignored.
4795 08 May 18 olle 48     <p>
4795 08 May 18 olle 49     If exactly one match is found this is the search for blood sample. More than one
4795 08 May 18 olle 50     match is an error condition. No match indicates a case that has not yet been
4795 08 May 18 olle 51     registered (null is returned).
4795 08 May 18 olle 52   */
4795 08 May 18 olle 53   public static Blood findByCaseName(DbControl dc, String name, boolean useBloodSampleAnnotation)
4795 08 May 18 olle 54   {
4795 08 May 18 olle 55     Blood bloodCase = null;
4795 08 May 18 olle 56     
4877 27 Jun 18 olle 57     SessionControl sc = dc.getSessionControl();
4795 08 May 18 olle 58     boolean preNeo = name.endsWith("C");
4877 27 Jun 18 olle 59     //if (name.length() > 7) name = name.substring(0, 7);
4877 27 Jun 18 olle 60     boolean bloodAndSampleItemPrefixesDiffer = Meludi.bloodAndSampleItemPrefixesDiffer(sc.getActiveProjectId());
4877 27 Jun 18 olle 61     if (!bloodAndSampleItemPrefixesDiffer)
4877 27 Jun 18 olle 62     {
4877 27 Jun 18 olle 63       name += ".b%";
4877 27 Jun 18 olle 64     }
4877 27 Jun 18 olle 65     else
4877 27 Jun 18 olle 66     {
4877 27 Jun 18 olle 67       name += ".%";      
4877 27 Jun 18 olle 68     }
4868 25 Jun 18 olle 69
4868 25 Jun 18 olle 70     // Replace sample item prefix with blood item prefix
4868 25 Jun 18 olle 71     String sampleItemPrefix = Meludi.fetchSampleItemPrefix(sc.getActiveProjectId());
4868 25 Jun 18 olle 72     String bloodItemPrefix = Meludi.fetchBloodItemPrefix(sc.getActiveProjectId());
4868 25 Jun 18 olle 73     if (name.startsWith(sampleItemPrefix))
4868 25 Jun 18 olle 74     {
4868 25 Jun 18 olle 75       // Remove sample item prefix
4868 25 Jun 18 olle 76       name = name.substring(sampleItemPrefix.length());
4868 25 Jun 18 olle 77       // Add blood item prefix
4868 25 Jun 18 olle 78       name = bloodItemPrefix + name;
4868 25 Jun 18 olle 79     }
4868 25 Jun 18 olle 80
4795 08 May 18 olle 81     // Look for a blood case with the given name 
4795 08 May 18 olle 82     ItemQuery<Sample> bloodQuery = Sample.getQuery();
4795 08 May 18 olle 83     Subtype.BLOOD.addFilter(dc, bloodQuery);
4795 08 May 18 olle 84     bloodQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.parameter("name", name, Type.STRING)));
4795 08 May 18 olle 85
4795 08 May 18 olle 86 /*
4795 08 May 18 olle 87     if (useBloodSampleAnnotation)
4795 08 May 18 olle 88     {
4795 08 May 18 olle 89       bloodQuery.join(Annotations.leftJoin(Annotationtype.BLOOD_SAMPLE.load(dc), "bs"));
4795 08 May 18 olle 90       if (preNeo)
4795 08 May 18 olle 91       {
4795 08 May 18 olle 92         // Only look for samples with annotation BloodSample=PreNeo
4795 08 May 18 olle 93         bloodQuery.restrict(Restrictions.eq(Hql.alias("bs"), Expressions.string("PreNeo")));
4795 08 May 18 olle 94       }
4795 08 May 18 olle 95       else
4795 08 May 18 olle 96       {
4795 08 May 18 olle 97         // Only look for samples with annotation BloodSample=PreOp or missing
4795 08 May 18 olle 98         bloodQuery.restrict(
4795 08 May 18 olle 99           Restrictions.or(
4795 08 May 18 olle 100             Restrictions.eq(Hql.alias("bs"), null),
4795 08 May 18 olle 101             Restrictions.eq(Hql.alias("bs"), Expressions.string("PreOp"))
4795 08 May 18 olle 102           ));
4795 08 May 18 olle 103       }
4795 08 May 18 olle 104     }
4795 08 May 18 olle 105 */
4795 08 May 18 olle 106     
4795 08 May 18 olle 107     List<Sample> bloodCases = bloodQuery.list(dc);
4795 08 May 18 olle 108     
4795 08 May 18 olle 109     // ...if more than one is found, something is incorrectly registered... abort
4795 08 May 18 olle 110     if (bloodCases.size() > 1)
4795 08 May 18 olle 111     {
4795 08 May 18 olle 112       throw new InvalidDataException(
4795 08 May 18 olle 113         "Found " + bloodCases.size() + " cases with the same name (" + name + 
4795 08 May 18 olle 114         "). This wizard can't be used until that is corrected.");
4795 08 May 18 olle 115     }
4795 08 May 18 olle 116     
4795 08 May 18 olle 117     if (bloodCases.size() == 1)
4795 08 May 18 olle 118     {
4795 08 May 18 olle 119       bloodCase = new Blood(bloodCases.get(0));
4795 08 May 18 olle 120     }
4795 08 May 18 olle 121     
4795 08 May 18 olle 122     return bloodCase;
4795 08 May 18 olle 123
4795 08 May 18 olle 124   }
4899 10 Jul 18 olle 125
4795 08 May 18 olle 126   /**
4795 08 May 18 olle 127     Find all blood information by case name without filtering on the 'BloodSample' annotation.
4795 08 May 18 olle 128     This method will check for  {@link Subtype#BLOOD} samples with a name matching the case name 
4795 08 May 18 olle 129     (eg. xxx.b).
4795 08 May 18 olle 130     @since 2.11
4795 08 May 18 olle 131   */
4795 08 May 18 olle 132   public static List<Blood> findAllByCaseName(DbControl dc, String name)
4795 08 May 18 olle 133   {
4899 10 Jul 18 olle 134     List<Blood> bloodList = null;
4899 10 Jul 18 olle 135
4899 10 Jul 18 olle 136     SessionControl sc = dc.getSessionControl();
4899 10 Jul 18 olle 137     boolean bloodAndSampleItemPrefixesDiffer = Meludi.bloodAndSampleItemPrefixesDiffer(sc.getActiveProjectId());
4899 10 Jul 18 olle 138     if (!bloodAndSampleItemPrefixesDiffer)
4899 10 Jul 18 olle 139     {
4899 10 Jul 18 olle 140       bloodList = findAllByCaseNameOldConvention(dc, name);
4899 10 Jul 18 olle 141     }
4899 10 Jul 18 olle 142     else
4899 10 Jul 18 olle 143     {
4899 10 Jul 18 olle 144       bloodList = findAllByCaseNameNewConvention(dc, name);
4899 10 Jul 18 olle 145     }
4899 10 Jul 18 olle 146
4899 10 Jul 18 olle 147     return bloodList;
4899 10 Jul 18 olle 148   }
4899 10 Jul 18 olle 149
4899 10 Jul 18 olle 150   /**
4899 10 Jul 18 olle 151     Find all blood information by case name without filtering on the 'BloodSample' annotation.
4899 10 Jul 18 olle 152     This method will check for  {@link Subtype#BLOOD} samples with a name matching the case name 
4899 10 Jul 18 olle 153     (eg. xxx.b).
4899 10 Jul 18 olle 154     @since 2.11
4899 10 Jul 18 olle 155   */
4899 10 Jul 18 olle 156   private static List<Blood> findAllByCaseNameOldConvention(DbControl dc, String name)
4899 10 Jul 18 olle 157   {
4795 08 May 18 olle 158     // Get rid of suffixes in the name (eg. 'C' which is used for pre-neoadjuvant forms)
4831 05 Jun 18 olle 159     //if (name.length() > 7) name = name.substring(0, 7);
4899 10 Jul 18 olle 160
4868 25 Jun 18 olle 161     // Replace sample item prefix with blood item prefix
4868 25 Jun 18 olle 162     SessionControl sc = dc.getSessionControl();
4868 25 Jun 18 olle 163     String sampleItemPrefix = Meludi.fetchSampleItemPrefix(sc.getActiveProjectId());
4868 25 Jun 18 olle 164     String bloodItemPrefix = Meludi.fetchBloodItemPrefix(sc.getActiveProjectId());
4868 25 Jun 18 olle 165     if (name.startsWith(sampleItemPrefix))
4868 25 Jun 18 olle 166     {
4868 25 Jun 18 olle 167       // Remove sample item prefix
4868 25 Jun 18 olle 168       name = name.substring(sampleItemPrefix.length());
4868 25 Jun 18 olle 169       // Add blood item prefix
4868 25 Jun 18 olle 170       name = bloodItemPrefix + name;
4868 25 Jun 18 olle 171     }
4868 25 Jun 18 olle 172
4795 08 May 18 olle 173     // Look for a blood case with the given name 
4795 08 May 18 olle 174     ItemQuery<Sample> bloodQuery = Sample.getQuery();
4795 08 May 18 olle 175     Subtype.BLOOD.addFilter(dc, bloodQuery);
4795 08 May 18 olle 176     bloodQuery.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT);
4795 08 May 18 olle 177     bloodQuery.restrict(Restrictions.like(Hql.property("name"), Expressions.parameter("name", name+".%", Type.STRING)));
4795 08 May 18 olle 178     bloodQuery.order(Orders.asc(Hql.property("name")));
4795 08 May 18 olle 179
4795 08 May 18 olle 180     List<Sample> tmp = bloodQuery.list(dc);
4899 10 Jul 18 olle 181     List<Blood> bloodList = new ArrayList<Blood>(tmp.size());
4795 08 May 18 olle 182     for (Sample s : tmp)
4795 08 May 18 olle 183     {
4899 10 Jul 18 olle 184       bloodList.add(new Blood(s));
4795 08 May 18 olle 185     }
4899 10 Jul 18 olle 186     return bloodList;
4795 08 May 18 olle 187   }
4795 08 May 18 olle 188
4795 08 May 18 olle 189   /**
4899 10 Jul 18 olle 190     Find all blood information by case name without filtering on the 'BloodSample' annotation.
4899 10 Jul 18 olle 191     This method will check for  {@link Subtype#BLOOD} samples with a CASE_ID annotation equal
4899 10 Jul 18 olle 192     to the case name. 
4899 10 Jul 18 olle 193     @since 2.11
4899 10 Jul 18 olle 194   */
4899 10 Jul 18 olle 195   private static List<Blood> findAllByCaseNameNewConvention(DbControl dc, String name)
4899 10 Jul 18 olle 196   {
4899 10 Jul 18 olle 197     // Look for a blood item with the given case ID as annotation.
4899 10 Jul 18 olle 198     String caseId = name;
4899 10 Jul 18 olle 199     AnnotationType caseIdType = Annotationtype.CASE_ID.load(dc);
4899 10 Jul 18 olle 200     ItemQuery<Sample> bloodQuery = Sample.getQuery();
4899 10 Jul 18 olle 201     Subtype.BLOOD.addFilter(dc, bloodQuery);
5468 04 Jun 19 olle 202     AnnotationRestriction.Options options = new AnnotationRestriction.Options();
5468 04 Jun 19 olle 203     options.setExcludeDefaultValues(false);
5468 04 Jun 19 olle 204     options.setIncludeInherited(false);
5468 04 Jun 19 olle 205     options.setIncludePrimary(true);
5468 04 Jun 19 olle 206     //bloodQuery.restrict(new AnnotationSimpleRestriction(null, caseIdType, Operator.EQ, caseId, true, false));
5468 04 Jun 19 olle 207     bloodQuery.restrict(new AnnotationSimpleRestriction(null, caseIdType, Operator.EQ, caseId, options));
4899 10 Jul 18 olle 208     bloodQuery.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT);
4899 10 Jul 18 olle 209     bloodQuery.order(Orders.asc(Hql.property("name")));
4899 10 Jul 18 olle 210
4899 10 Jul 18 olle 211     List<Sample> tmp = bloodQuery.list(dc);
4899 10 Jul 18 olle 212     List<Blood> bloodList = new ArrayList<Blood>(tmp.size());
4899 10 Jul 18 olle 213     for (Sample s : tmp)
4899 10 Jul 18 olle 214     {
4899 10 Jul 18 olle 215       bloodList.add(new Blood(s));
4899 10 Jul 18 olle 216     }
4899 10 Jul 18 olle 217     return bloodList;
4899 10 Jul 18 olle 218   }
4899 10 Jul 18 olle 219
4899 10 Jul 18 olle 220   /**
4795 08 May 18 olle 221      Find a blood item with the given external ID.
4795 08 May 18 olle 222      @return A blood item, or null if not found
4795 08 May 18 olle 223      @since 4.7
4795 08 May 18 olle 224   */
4795 08 May 18 olle 225   public static Blood findByExternalId(DbControl dc, String externalId)
4795 08 May 18 olle 226   {
4795 08 May 18 olle 227     Blood item = null;
4795 08 May 18 olle 228     
4795 08 May 18 olle 229     ItemQuery<Sample> query = Sample.getQuery();
4795 08 May 18 olle 230     Subtype.BLOOD.addFilter(dc, query);
4795 08 May 18 olle 231     query.restrict(Restrictions.eq(Hql.property("externalId"), Expressions.string(externalId)));
4795 08 May 18 olle 232     query.order(Orders.desc(Hql.property("name")));
4795 08 May 18 olle 233     query.setIncludes(Meludi.INCLUDE_IN_CURRENT_PROJECT);
4795 08 May 18 olle 234     
4795 08 May 18 olle 235     List<Sample> items = query.list(dc);
4795 08 May 18 olle 236     if (items.size() > 1)
4795 08 May 18 olle 237     {
4795 08 May 18 olle 238       throw new InvalidDataException(
4795 08 May 18 olle 239           "More than one blood item with the external id '" + externalId + "' was found. " +
4795 08 May 18 olle 240           "This wizard can't be used until that is corrected.");
4795 08 May 18 olle 241     }
4795 08 May 18 olle 242     if (items.size() == 1)
4795 08 May 18 olle 243     {
4795 08 May 18 olle 244       item = new Blood(items.get(0));
4795 08 May 18 olle 245     }
4795 08 May 18 olle 246     return item;
4795 08 May 18 olle 247   }
4795 08 May 18 olle 248
4795 08 May 18 olle 249   
4795 08 May 18 olle 250   /**
4795 08 May 18 olle 251     Find all blood information linked with a patient. A patient can have any
4795 08 May 18 olle 252     number of blood cases.
4795 08 May 18 olle 253   */
4795 08 May 18 olle 254   public static List<Blood> findByPatient(DbControl dc, Patient patient)
4795 08 May 18 olle 255   {
4795 08 May 18 olle 256     ItemQuery<Sample> bloodQuery = patient.getBioSource().getSamples();
4795 08 May 18 olle 257     Subtype.BLOOD.addFilter(dc, bloodQuery);
4795 08 May 18 olle 258     bloodQuery.include(Include.ALL);
4795 08 May 18 olle 259     bloodQuery.order(Orders.asc(Hql.property("name")));
4795 08 May 18 olle 260     List<Sample> tmp = bloodQuery.list(dc);
4795 08 May 18 olle 261     List<Blood> blood = new ArrayList<Blood>(tmp.size());
4795 08 May 18 olle 262     for (Sample s : tmp)
4795 08 May 18 olle 263     {
4795 08 May 18 olle 264       blood.add(new Blood(s));
4795 08 May 18 olle 265     }
4795 08 May 18 olle 266     return blood;
4795 08 May 18 olle 267   }
4795 08 May 18 olle 268   
4795 08 May 18 olle 269   /**
4795 08 May 18 olle 270     Find blood information by RCCID number. This method will check for 
4795 08 May 18 olle 271     {@link Subtype#BLOOD} samples annotated with BloodRccidNumber=name.
4795 08 May 18 olle 272     <p>
4795 08 May 18 olle 273     If exactly one match is found this is the search for blood sample. More than one
4795 08 May 18 olle 274     match is an error condition. No match indicates an RCCID number that has not yet been
4795 08 May 18 olle 275     registered (null is returned).
4795 08 May 18 olle 276     
4795 08 May 18 olle 277     @param dc DbControl The DbControl to use to connect to the database.
4795 08 May 18 olle 278     @param name String The RCCID number to find a blood sample for.
4795 08 May 18 olle 279     @return Blood A blood item with the input RCCID number, or null if not found.
4795 08 May 18 olle 280     @since 2.13
4795 08 May 18 olle 281    */
4795 08 May 18 olle 282   public static Blood findByRccidNumber(DbControl dc, String name)
4795 08 May 18 olle 283   {
4795 08 May 18 olle 284     Blood blood = null;
4795 08 May 18 olle 285
4795 08 May 18 olle 286     // Only follow-up blood samples have non-blank RCCID numbers.
4795 08 May 18 olle 287     // Return null if input RCCID number is null or empty string.
4795 08 May 18 olle 288     if (name == null || name.equals(""))
4795 08 May 18 olle 289     {
4795 08 May 18 olle 290       return null;
4795 08 May 18 olle 291     }
4795 08 May 18 olle 292
4795 08 May 18 olle 293     // Look for a blood sample with annotation BloodRccidNumber=name
4795 08 May 18 olle 294     ItemQuery<Sample> bloodQuery = Sample.getQuery();
4795 08 May 18 olle 295     Subtype.BLOOD.addFilter(dc, bloodQuery);
4795 08 May 18 olle 296     //bloodQuery.restrict(new AnnotationSimpleRestriction(null, Annotationtype.BLOOD_RCCIDNUMBER.load(dc), Operator.EQ, name, true, false));
4795 08 May 18 olle 297     
4795 08 May 18 olle 298     List<Sample> bloodSamples = bloodQuery.list(dc);
4795 08 May 18 olle 299   
4795 08 May 18 olle 300     // ...if more than one is found, something is incorrectly registered... abort
4795 08 May 18 olle 301     if (bloodSamples.size() > 1)
4795 08 May 18 olle 302     {
4795 08 May 18 olle 303       throw new InvalidDataException(
4795 08 May 18 olle 304           "Found " + bloodSamples.size() + " blood samples with same RCCID number (" + name + 
4795 08 May 18 olle 305           "). This wizard can't be used until that is corrected.");
4795 08 May 18 olle 306     }
4795 08 May 18 olle 307   
4795 08 May 18 olle 308     if (bloodSamples.size() == 1)
4795 08 May 18 olle 309     {
4795 08 May 18 olle 310       blood = new Blood(bloodSamples.get(0));
4795 08 May 18 olle 311     }
4795 08 May 18 olle 312   
4795 08 May 18 olle 313     return blood;
4795 08 May 18 olle 314   }
4795 08 May 18 olle 315
4795 08 May 18 olle 316   /**
4795 08 May 18 olle 317     Find all blood information by base RCCID number, i.e. the RCCID number disregarding the suffix
4795 08 May 18 olle 318     letter 'B', 'C', or 'D'. This method will check for {@link Subtype#BLOOD} samples annotated
4795 08 May 18 olle 319     with BloodRccidNumber=rccidNumber, where rccidNumber is input name string with suffix letter
4795 08 May 18 olle 320     exchanged for 'B', 'C', and 'D'.
4795 08 May 18 olle 321     <p>
4795 08 May 18 olle 322     No match indicates an RCCID number that has not yet been registered (null is returned).
4795 08 May 18 olle 323     
4795 08 May 18 olle 324     @param dc DbControl The DbControl to use to connect to the database.
4795 08 May 18 olle 325     @param name String The RCCID number to find a blood sample for.
4795 08 May 18 olle 326     @return Blood A blood item with the input RCCID number, or null if not found.
4795 08 May 18 olle 327     @since 2.13
4795 08 May 18 olle 328    */
4795 08 May 18 olle 329   public static List<Blood> findAllByBaseRccidNumber(DbControl dc, String name)
4795 08 May 18 olle 330   {
4795 08 May 18 olle 331     // Only follow-up blood samples have non-blank RCCID numbers.
4795 08 May 18 olle 332     // Return null if input RCCID number is null or empty string.
4795 08 May 18 olle 333     if (name == null || name.equals(""))
4795 08 May 18 olle 334     {
4795 08 May 18 olle 335       return null;
4795 08 May 18 olle 336     }
4795 08 May 18 olle 337
4795 08 May 18 olle 338     // Get base RCCID number (RCCID number without suffix letter 'B', 'C', or 'D')
4795 08 May 18 olle 339     String baseRccidNumber = name;
4795 08 May 18 olle 340     if (name.endsWith("B") || name.endsWith("C") || name.endsWith("D"))
4795 08 May 18 olle 341     {
4795 08 May 18 olle 342       // Set base RCCID number as name with last character removed
4795 08 May 18 olle 343       baseRccidNumber = name.substring(0, name.length() - 1);
4795 08 May 18 olle 344     }
4795 08 May 18 olle 345     // Check for blood samples with base RCCID number 
4795 08 May 18 olle 346     List<Blood> bloodSampleList = new ArrayList<Blood>();
4795 08 May 18 olle 347     String rccidNumber = "";
4795 08 May 18 olle 348     for (int i = 0; i < 3; i++)
4795 08 May 18 olle 349     {
4795 08 May 18 olle 350       String suffix = "B";
4795 08 May 18 olle 351       if (i == 1)
4795 08 May 18 olle 352       {
4795 08 May 18 olle 353         suffix = "C";
4795 08 May 18 olle 354       }
4795 08 May 18 olle 355       else if (i == 2)
4795 08 May 18 olle 356       {
4795 08 May 18 olle 357         suffix = "D";
4795 08 May 18 olle 358       }
4795 08 May 18 olle 359       rccidNumber = baseRccidNumber + suffix;
4795 08 May 18 olle 360       // Look for a blood sample with annotation BloodRccidNumber=rccidNumber
4795 08 May 18 olle 361       ItemQuery<Sample> bloodQuery = Sample.getQuery();
4795 08 May 18 olle 362       Subtype.BLOOD.addFilter(dc, bloodQuery);
4795 08 May 18 olle 363       //bloodQuery.restrict(new AnnotationSimpleRestriction(null, Annotationtype.BLOOD_RCCIDNUMBER.load(dc), Operator.EQ, rccidNumber, true, false));
4795 08 May 18 olle 364       
4795 08 May 18 olle 365       List<Sample> bloodSamples = bloodQuery.list(dc);
4795 08 May 18 olle 366       if (bloodSamples.size() == 1)
4795 08 May 18 olle 367       {
4795 08 May 18 olle 368         Blood blood = new Blood(bloodSamples.get(0));
4795 08 May 18 olle 369         bloodSampleList.add(blood);
4795 08 May 18 olle 370       }
4795 08 May 18 olle 371     }
4795 08 May 18 olle 372     // Return null if no blood samples were found with input base RCCID number 
4795 08 May 18 olle 373     if (bloodSampleList.size() == 0)
4795 08 May 18 olle 374     {
4795 08 May 18 olle 375       bloodSampleList = null;
4795 08 May 18 olle 376     }
4795 08 May 18 olle 377
4795 08 May 18 olle 378     return bloodSampleList;
4795 08 May 18 olle 379   }
4795 08 May 18 olle 380
4795 08 May 18 olle 381   /**
4795 08 May 18 olle 382     Generate the next auto-generated blood name. This method will search all blood 
4795 08 May 18 olle 383     samples starting with the given prefix and find the one with the highest numeric 
4795 08 May 18 olle 384     suffix. The returned name is the found blood + 1.
4795 08 May 18 olle 385     @since 2.5
4795 08 May 18 olle 386   */
4795 08 May 18 olle 387   public static String generateNextName(DbControl dc, String prefix, Subtype subtype)
4795 08 May 18 olle 388   {
4795 08 May 18 olle 389     ItemQuery<Sample> bloodQuery = Sample.getQuery();
4795 08 May 18 olle 390     if (subtype != null) subtype.addFilter(dc, bloodQuery);
4795 08 May 18 olle 391     bloodQuery.restrict(Restrictions.rlike(Hql.property("name"), Expressions.string("^" + prefix + "[0-9]*$")));
4795 08 May 18 olle 392     bloodQuery.order(Orders.desc(Hql.property("name")));
4795 08 May 18 olle 393     bloodQuery.setMaxResults(1);
4795 08 May 18 olle 394     bloodQuery.include(Include.ALL);
4795 08 May 18 olle 395     List<Sample> blood = bloodQuery.list(dc);
4795 08 May 18 olle 396     String name = null;
4795 08 May 18 olle 397     if (blood.size() == 0)
4795 08 May 18 olle 398     {
4795 08 May 18 olle 399       // First blood sample should not have any numeric suffix
4795 08 May 18 olle 400       name = prefix;
4795 08 May 18 olle 401     }
4795 08 May 18 olle 402     else
4795 08 May 18 olle 403     {
4795 08 May 18 olle 404       String suffix = blood.get(0).getName().substring(prefix.length());
4795 08 May 18 olle 405       int nextSuffix = Values.getInt(suffix, 1) + 1;
4795 08 May 18 olle 406       name = prefix + nextSuffix;
4795 08 May 18 olle 407     }
4795 08 May 18 olle 408     return name;
4795 08 May 18 olle 409   }
4795 08 May 18 olle 410   
4795 08 May 18 olle 411   // Reserve external ids for 5 minutes
4795 08 May 18 olle 412   private static final ReservedItems<Integer> RESERVED_EXTERNAL_IDS = new ReservedItems<Integer>(300);
4795 08 May 18 olle 413
4795 08 May 18 olle 414   /**
4795 08 May 18 olle 415     Generate the next auto-generated external ID. This method will search all blood
4795 08 May 18 olle 416     starting with the given prefix and find the one with the highest numeric suffix. 
4795 08 May 18 olle 417     The returned string is the found blood + 1. This method uses the
4795 08 May 18 olle 418     {@link ReservedItems} to make sure that the same id is not generated
4795 08 May 18 olle 419     twice.
4795 08 May 18 olle 420     @since 4.7
4795 08 May 18 olle 421   */
4795 08 May 18 olle 422   public static String generateNextExternalId(DbControl dc, String prefix)
4795 08 May 18 olle 423   {
4795 08 May 18 olle 424     ItemQuery<Sample> bloodQuery = Sample.getQuery();
4795 08 May 18 olle 425     Subtype.BLOOD.addFilter(dc, bloodQuery);
4795 08 May 18 olle 426     bloodQuery.restrict(Restrictions.rlike(Hql.property("externalId"), Expressions.string("^" + prefix + "[0-9]+$")));
4795 08 May 18 olle 427     bloodQuery.order(Orders.desc(Hql.property("externalId")));
4795 08 May 18 olle 428     bloodQuery.setMaxResults(1);
4795 08 May 18 olle 429     bloodQuery.include(Include.ALL);
4795 08 May 18 olle 430     List<Sample> blood = bloodQuery.list(dc);
4795 08 May 18 olle 431     
4795 08 May 18 olle 432     int nextExternalNumber = 1;
4795 08 May 18 olle 433     if (blood.size() > 0)
4795 08 May 18 olle 434     {
4795 08 May 18 olle 435       String externalNumber = blood.get(0).getExternalId().substring(prefix.length());
4795 08 May 18 olle 436       nextExternalNumber = Integer.parseInt(externalNumber) + 1;
4795 08 May 18 olle 437     }
4795 08 May 18 olle 438     int maxExternalNumber = 100+nextExternalNumber;
4795 08 May 18 olle 439     while (!RESERVED_EXTERNAL_IDS.reserve(nextExternalNumber))
4795 08 May 18 olle 440     {
4795 08 May 18 olle 441       nextExternalNumber++;
4795 08 May 18 olle 442       if (nextExternalNumber == maxExternalNumber)
4795 08 May 18 olle 443       {
4795 08 May 18 olle 444         throw new RuntimeException("Failed to generate an external ID after 100 tries");
4795 08 May 18 olle 445       }
4795 08 May 18 olle 446     }
4795 08 May 18 olle 447     String externalId = prefix + MD5.leftPad(Integer.toString(nextExternalNumber), '0', 6);
4795 08 May 18 olle 448     return externalId;
4795 08 May 18 olle 449   }
4795 08 May 18 olle 450
4795 08 May 18 olle 451   /**
4795 08 May 18 olle 452     Load a blood sample given the exact name of the item.
4795 08 May 18 olle 453     @since 2.5
4795 08 May 18 olle 454   */
4795 08 May 18 olle 455   public static Blood getByName(DbControl dc, String name)
4795 08 May 18 olle 456   {
4795 08 May 18 olle 457     Blood blood = null;
4795 08 May 18 olle 458     
4795 08 May 18 olle 459     // Look for a blood case with the given name 
4795 08 May 18 olle 460     ItemQuery<Sample> bloodQuery = Sample.getQuery();
4795 08 May 18 olle 461     Subtype.BLOOD.addFilter(dc, bloodQuery);
4795 08 May 18 olle 462     bloodQuery.restrict(Restrictions.eq(Hql.property("name"), Expressions.parameter("name", name, Type.STRING)));
4795 08 May 18 olle 463     
4795 08 May 18 olle 464     List<Sample> bloodSamples = bloodQuery.list(dc);
4795 08 May 18 olle 465     
4795 08 May 18 olle 466     // ...if more than one is found, something is incorrectly registered... abort
4795 08 May 18 olle 467     if (bloodSamples.size() > 1)
4795 08 May 18 olle 468     {
4795 08 May 18 olle 469       throw new InvalidDataException(
4795 08 May 18 olle 470         "Found " + bloodSamples.size() + " blood samples with the same name (" + name + 
4795 08 May 18 olle 471         "). This wizard can't be used until that is corrected.");
4795 08 May 18 olle 472     }
4795 08 May 18 olle 473     
4795 08 May 18 olle 474     if (bloodSamples.size() == 1)
4795 08 May 18 olle 475     {
4795 08 May 18 olle 476       blood = new Blood(bloodSamples.get(0));
4795 08 May 18 olle 477     }
4795 08 May 18 olle 478     
4795 08 May 18 olle 479     return blood;
4795 08 May 18 olle 480   }
4795 08 May 18 olle 481   
4795 08 May 18 olle 482   public static Blood getById(DbControl dc, int caseId)
4795 08 May 18 olle 483   {
4795 08 May 18 olle 484     Sample s = Sample.getById(dc, caseId);
4795 08 May 18 olle 485     return s == null ? null : new Blood(s);
4795 08 May 18 olle 486   }
4795 08 May 18 olle 487   
4795 08 May 18 olle 488   private Blood(Sample sample)
4795 08 May 18 olle 489   {
4795 08 May 18 olle 490     super(sample);
4795 08 May 18 olle 491   }
4795 08 May 18 olle 492   
4795 08 May 18 olle 493   
4795 08 May 18 olle 494   /**
4795 08 May 18 olle 495     Get the real sample that represents this case in BASE.
4795 08 May 18 olle 496   */
4795 08 May 18 olle 497   public Sample getSample()
4795 08 May 18 olle 498   {
4795 08 May 18 olle 499     return getItem();
4795 08 May 18 olle 500   }
4831 05 Jun 18 olle 501
4831 05 Jun 18 olle 502   private JSONObject jsonWell;
4831 05 Jun 18 olle 503
4831 05 Jun 18 olle 504   @SuppressWarnings("unchecked")
4831 05 Jun 18 olle 505   @Override
4831 05 Jun 18 olle 506   protected void initJSON(JSONObject json)
4831 05 Jun 18 olle 507   {
4831 05 Jun 18 olle 508     super.initJSON(json);
4831 05 Jun 18 olle 509     if (jsonWell != null) json.put("bioWell", jsonWell);
4831 05 Jun 18 olle 510   }
4795 08 May 18 olle 511   
4795 08 May 18 olle 512   /**
4831 05 Jun 18 olle 513     Load information about the plate and location the current Blood
4831 05 Jun 18 olle 514     is located on.
4831 05 Jun 18 olle 515   */
4831 05 Jun 18 olle 516   public JSONObject loadBioPlateLocation()
4831 05 Jun 18 olle 517   {
4831 05 Jun 18 olle 518     if (jsonWell == null)
4831 05 Jun 18 olle 519     {
4831 05 Jun 18 olle 520       jsonWell = JsonUtil.getBioWellAsJSON(getItem().getBioWell(), true);
4831 05 Jun 18 olle 521     }
4831 05 Jun 18 olle 522     return jsonWell;
4831 05 Jun 18 olle 523   }
4831 05 Jun 18 olle 524   
4831 05 Jun 18 olle 525   /**
4795 08 May 18 olle 526     Verify that the patient has given their permission to participate in the
4795 08 May 18 olle 527     study. Due to the order that things get registered, a non-existing "Consent"
4795 08 May 18 olle 528     annotation is accepted. If the annotation exists the answer must be "Yes",
4795 08 May 18 olle 529     or an exception is thrown.
4795 08 May 18 olle 530   */
4795 08 May 18 olle 531   public void verifyConsent(DbControl dc, Annotationtype consentType)
4795 08 May 18 olle 532   {
4795 08 May 18 olle 533     if (consentType == null)
4795 08 May 18 olle 534     {
4795 08 May 18 olle 535       consentType = Annotationtype.CONSENT;
4795 08 May 18 olle 536     }
4795 08 May 18 olle 537     String consent = (String)consentType.getAnnotationValue(dc, getItem());
4795 08 May 18 olle 538     if (consent != null && !consent.equals("Yes"))
4795 08 May 18 olle 539     {
4795 08 May 18 olle 540       throw new PermissionDeniedException("The case (" + getName() + 
4795 08 May 18 olle 541         ") has not agreed to participate in the study.");
4795 08 May 18 olle 542     }
4795 08 May 18 olle 543
4795 08 May 18 olle 544   }
4795 08 May 18 olle 545   
4795 08 May 18 olle 546 }