extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/servlet/ExportServlet.java

Code
Comments
Other
Rev Date Author Line
1634 02 May 12 nicklas 1 package net.sf.basedb.reggie.servlet;
1634 02 May 12 nicklas 2
4627 21 Nov 17 nicklas 3 import java.io.BufferedReader;
4627 21 Nov 17 nicklas 4 import java.io.FileNotFoundException;
1634 02 May 12 nicklas 5 import java.io.IOException;
4627 21 Nov 17 nicklas 6 import java.io.InputStream;
4627 21 Nov 17 nicklas 7 import java.io.InputStreamReader;
4627 21 Nov 17 nicklas 8 import java.io.OutputStream;
4627 21 Nov 17 nicklas 9 import java.io.OutputStreamWriter;
1634 02 May 12 nicklas 10 import java.io.PrintWriter;
5663 11 Oct 19 nicklas 11 import java.util.ArrayList;
1634 02 May 12 nicklas 12 import java.util.Calendar;
5663 11 Oct 19 nicklas 13 import java.util.Collections;
5663 11 Oct 19 nicklas 14 import java.util.Comparator;
1634 02 May 12 nicklas 15 import java.util.Date;
1957 30 Apr 13 olle 16 import java.util.HashMap;
3914 02 May 16 nicklas 17 import java.util.Iterator;
1634 02 May 12 nicklas 18 import java.util.List;
1634 02 May 12 nicklas 19 import java.util.Set;
4627 21 Nov 17 nicklas 20 import java.util.TimerTask;
1634 02 May 12 nicklas 21 import java.util.TreeSet;
1680 31 May 12 nicklas 22 import java.util.regex.Pattern;
1634 02 May 12 nicklas 23
5332 20 Mar 19 nicklas 24 import javax.crypto.Cipher;
5332 20 Mar 19 nicklas 25 import javax.crypto.CipherInputStream;
5332 20 Mar 19 nicklas 26 import javax.crypto.CipherOutputStream;
1634 02 May 12 nicklas 27 import javax.servlet.ServletException;
1634 02 May 12 nicklas 28 import javax.servlet.http.HttpServlet;
1634 02 May 12 nicklas 29 import javax.servlet.http.HttpServletRequest;
1634 02 May 12 nicklas 30 import javax.servlet.http.HttpServletResponse;
1634 02 May 12 nicklas 31
4627 21 Nov 17 nicklas 32 import org.json.simple.JSONArray;
2603 27 Aug 14 nicklas 33 import org.json.simple.JSONObject;
2603 27 Aug 14 nicklas 34
4627 21 Nov 17 nicklas 35 import net.sf.basedb.clients.web.fileupload.FileUpload;
4627 21 Nov 17 nicklas 36 import net.sf.basedb.clients.web.fileupload.FileUploadProgress;
4627 21 Nov 17 nicklas 37 import net.sf.basedb.clients.web.fileupload.UploadedFile;
4627 21 Nov 17 nicklas 38 import net.sf.basedb.core.Application;
1634 02 May 12 nicklas 39 import net.sf.basedb.core.BioMaterial;
1634 02 May 12 nicklas 40 import net.sf.basedb.core.BioSource;
1634 02 May 12 nicklas 41 import net.sf.basedb.core.DbControl;
5663 11 Oct 19 nicklas 42 import net.sf.basedb.core.Item;
1634 02 May 12 nicklas 43 import net.sf.basedb.core.ItemQuery;
4717 28 Mar 18 nicklas 44 import net.sf.basedb.core.ItemResultIterator;
1957 30 Apr 13 olle 45 import net.sf.basedb.core.ItemSubtype;
1957 30 Apr 13 olle 46 import net.sf.basedb.core.MeasuredBioMaterial;
3914 02 May 16 nicklas 47 import net.sf.basedb.core.ProgressReporter;
1634 02 May 12 nicklas 48 import net.sf.basedb.core.Sample;
1634 02 May 12 nicklas 49 import net.sf.basedb.core.SessionControl;
3904 29 Apr 16 nicklas 50 import net.sf.basedb.core.SimpleProgressReporter;
4627 21 Nov 17 nicklas 51 import net.sf.basedb.core.Type;
2605 27 Aug 14 nicklas 52 import net.sf.basedb.core.query.Annotations;
1634 02 May 12 nicklas 53 import net.sf.basedb.core.query.Expressions;
1634 02 May 12 nicklas 54 import net.sf.basedb.core.query.Hql;
2206 31 Jan 14 olle 55 import net.sf.basedb.core.query.Orders;
1634 02 May 12 nicklas 56 import net.sf.basedb.core.query.Restrictions;
1676 31 May 12 nicklas 57 import net.sf.basedb.core.snapshot.SnapshotManager;
2603 27 Aug 14 nicklas 58 import net.sf.basedb.reggie.JsonUtil;
1672 30 May 12 nicklas 59 import net.sf.basedb.reggie.Reggie;
1634 02 May 12 nicklas 60 import net.sf.basedb.reggie.Site;
5663 11 Oct 19 nicklas 61 import net.sf.basedb.reggie.converter.ValueConverter;
5332 20 Mar 19 nicklas 62 import net.sf.basedb.reggie.crypto.CryptoUtil;
1634 02 May 12 nicklas 63 import net.sf.basedb.reggie.dao.Annotationtype;
2161 09 Dec 13 nicklas 64 import net.sf.basedb.reggie.dao.ReggieRole;
1634 02 May 12 nicklas 65 import net.sf.basedb.reggie.dao.Subtype;
1672 30 May 12 nicklas 66 import net.sf.basedb.util.EqualsHelper;
4627 21 Nov 17 nicklas 67 import net.sf.basedb.util.FileUtil;
5332 20 Mar 19 nicklas 68 import net.sf.basedb.util.MD5;
5332 20 Mar 19 nicklas 69 import net.sf.basedb.util.StaticCache;
1634 02 May 12 nicklas 70 import net.sf.basedb.util.Values;
2603 27 Aug 14 nicklas 71 import net.sf.basedb.util.error.ThrowableUtil;
4627 21 Nov 17 nicklas 72 import net.sf.basedb.util.export.TableWriter;
1634 02 May 12 nicklas 73 import net.sf.basedb.util.formatter.DateFormatter;
5663 11 Oct 19 nicklas 74 import net.sf.basedb.util.formatter.Formatter;
1634 02 May 12 nicklas 75
1634 02 May 12 nicklas 76
1634 02 May 12 nicklas 77 public class ExportServlet 
1634 02 May 12 nicklas 78   extends HttpServlet 
1634 02 May 12 nicklas 79 {
1634 02 May 12 nicklas 80
1634 02 May 12 nicklas 81   private static final long serialVersionUID = 5134386187393673271L;
1634 02 May 12 nicklas 82
1634 02 May 12 nicklas 83   public ExportServlet()
1634 02 May 12 nicklas 84   {}
1634 02 May 12 nicklas 85
1634 02 May 12 nicklas 86   @Override
1634 02 May 12 nicklas 87   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
1634 02 May 12 nicklas 88     throws ServletException, IOException 
1634 02 May 12 nicklas 89   {
1634 02 May 12 nicklas 90     String cmd = req.getParameter("cmd");
2603 27 Aug 14 nicklas 91     boolean useJsonForError = false;
3904 29 Apr 16 nicklas 92     String progressName = req.getParameter("progressbar");
3904 29 Apr 16 nicklas 93     SimpleProgressReporter progress = null;
1634 02 May 12 nicklas 94   
3975 26 May 16 nicklas 95     final SessionControl sc = Reggie.getSessionControl(req);
3904 29 Apr 16 nicklas 96     if (progressName != null)
3904 29 Apr 16 nicklas 97     {
3904 29 Apr 16 nicklas 98       progress = new SimpleProgressReporter(null);
3904 29 Apr 16 nicklas 99       sc.setSessionSetting(progressName, progress);
3904 29 Apr 16 nicklas 100     }
1634 02 May 12 nicklas 101     DbControl dc = null;
1634 02 May 12 nicklas 102     try
1634 02 May 12 nicklas 103     {
1957 30 Apr 13 olle 104       if ("ExportMonthlyOpList".equals(cmd) || "ExportINCA".equals(cmd))
1634 02 May 12 nicklas 105       {
6336 16 Jun 21 nicklas 106         dc = sc.newDbControl("ExportINCA".equals(cmd) ? ":INCA export" : ":Export monthly operation list");
2607 28 Aug 14 nicklas 107         useJsonForError = Values.getBoolean(req.getParameter("preview"));
3904 29 Apr 16 nicklas 108         
3904 29 Apr 16 nicklas 109         if (progress != null)
3904 29 Apr 16 nicklas 110         {
3904 29 Apr 16 nicklas 111           progress.display(1, "Loading samples...");
3904 29 Apr 16 nicklas 112         }
2161 09 Dec 13 nicklas 113
2161 09 Dec 13 nicklas 114         ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.PATIENT_CURATOR, ReggieRole.ADMINISTRATOR);
2161 09 Dec 13 nicklas 115
1673 30 May 12 nicklas 116         boolean exportSubtype = Values.getBoolean(req.getParameter("exportSubtype"));
1740 22 Nov 12 nicklas 117         boolean exportPatientId = Values.getBoolean(req.getParameter("exportPatientId"));
2603 27 Aug 14 nicklas 118
1674 30 May 12 nicklas 119         // This can be any time point in the desired month/year
1674 30 May 12 nicklas 120         long timeInMillis = Values.getLong(req.getParameter("time"));
1957 30 Apr 13 olle 121         // A value of 1 (1970.01.01 00:00:00 001) indicates no time restriction
1957 30 Apr 13 olle 122         boolean allSamples = (timeInMillis == 1);
1957 30 Apr 13 olle 123         // Negative value indicates that we should load the whole year
1674 30 May 12 nicklas 124         boolean fullYear = timeInMillis < 0;
1674 30 May 12 nicklas 125         timeInMillis = Math.abs(timeInMillis);
1634 02 May 12 nicklas 126         
1674 30 May 12 nicklas 127         Calendar time = Calendar.getInstance();
1674 30 May 12 nicklas 128         time.setTimeInMillis(timeInMillis);
1674 30 May 12 nicklas 129         // Set to first day in the current month
1674 30 May 12 nicklas 130         time.set(Calendar.HOUR, 0);
1674 30 May 12 nicklas 131         time.set(Calendar.MINUTE, 0);
1674 30 May 12 nicklas 132         time.set(Calendar.SECOND, 0);
1674 30 May 12 nicklas 133         time.set(Calendar.MILLISECOND, 0);
1674 30 May 12 nicklas 134         time.set(Calendar.DAY_OF_MONTH, 1);
1674 30 May 12 nicklas 135         // Set to first month of year
1674 30 May 12 nicklas 136         if (fullYear) time.set(Calendar.MONTH, 0);
1634 02 May 12 nicklas 137         
1674 30 May 12 nicklas 138         // We now have our start time
1674 30 May 12 nicklas 139         Date start = time.getTime();
1634 02 May 12 nicklas 140         
1674 30 May 12 nicklas 141         // Add one month or year -- this is our end time
1674 30 May 12 nicklas 142         time.add(fullYear ? Calendar.YEAR : Calendar.MONTH, 1);
1674 30 May 12 nicklas 143         Date end = time.getTime();
1674 30 May 12 nicklas 144         
1634 02 May 12 nicklas 145         // Load sample items...
1634 02 May 12 nicklas 146         ItemQuery<Sample> specimenQuery = Sample.getQuery();
1634 02 May 12 nicklas 147         
1634 02 May 12 nicklas 148         // ...that has a creation date (=operation date) between the start and end time points
1634 02 May 12 nicklas 149         specimenQuery.join(Hql.innerJoin(null, "creationEvent", "ce", true));
1957 30 Apr 13 olle 150         if (!allSamples)
1957 30 Apr 13 olle 151         {
1957 30 Apr 13 olle 152           specimenQuery.restrict(Restrictions.gteq(Hql.property("ce", "eventDate"), Expressions.parameter("start", start)));
1957 30 Apr 13 olle 153           specimenQuery.restrict(Restrictions.lt(Hql.property("ce", "eventDate"), Expressions.parameter("end", end)));
1957 30 Apr 13 olle 154         }
1957 30 Apr 13 olle 155
1957 30 Apr 13 olle 156         if ("ExportMonthlyOpList".equals(cmd))
1957 30 Apr 13 olle 157         {
1957 30 Apr 13 olle 158           // FETCH JOIN of CASE and PATIENT + the CASE creation event
1957 30 Apr 13 olle 159           // for performance reasons
1957 30 Apr 13 olle 160           specimenQuery.join(Hql.innerJoin(null, "parent", "cse", true));
1957 30 Apr 13 olle 161           specimenQuery.join(Hql.innerJoin("cse", "creationEvent", "ce2", true));
1957 30 Apr 13 olle 162           specimenQuery.join(Hql.innerJoin("cse", "parent", "pat", true));
1957 30 Apr 13 olle 163           
1957 30 Apr 13 olle 164           // ...only include 'Specimen' or 'NoSpecimen' items
1957 30 Apr 13 olle 165           specimenQuery.restrict(
1957 30 Apr 13 olle 166             Restrictions.or(
1957 30 Apr 13 olle 167               Subtype.SPECIMEN.restriction(dc, null),
6510 03 Dec 21 nicklas 168               Subtype.NO_SPECIMEN.restriction(dc, null)
1957 30 Apr 13 olle 169             ));
1957 30 Apr 13 olle 170         }
1957 30 Apr 13 olle 171         else if ("ExportINCA".equals(cmd))
1957 30 Apr 13 olle 172         {
2674 16 Sep 14 nicklas 173           // FETCH JOIN one parent up
2674 16 Sep 14 nicklas 174           specimenQuery.join(Hql.innerJoin(null, "parent", "pp", true));
1957 30 Apr 13 olle 175           // ...include 'Specimen', 'NoSpecimen', and 'Blood' items
1957 30 Apr 13 olle 176           specimenQuery.restrict(
1957 30 Apr 13 olle 177             Restrictions.or(
1957 30 Apr 13 olle 178               Subtype.SPECIMEN.restriction(dc, null),
1957 30 Apr 13 olle 179               Subtype.NO_SPECIMEN.restriction(dc, null),
1957 30 Apr 13 olle 180               Subtype.BLOOD.restriction(dc, null)
1957 30 Apr 13 olle 181             ));
1957 30 Apr 13 olle 182         }
1634 02 May 12 nicklas 183         
3904 29 Apr 16 nicklas 184         
4717 28 Mar 18 nicklas 185         specimenQuery.setReturnTotalCount(true);
4717 28 Mar 18 nicklas 186         ItemResultIterator<Sample> samples = specimenQuery.iterate(dc);
4717 28 Mar 18 nicklas 187         long totalCount = samples.getTotalCount();
1676 31 May 12 nicklas 188         
1676 31 May 12 nicklas 189         // Use stored annotation snapshots for performance reasons
1676 31 May 12 nicklas 190         SnapshotManager manager = new SnapshotManager();        
1634 02 May 12 nicklas 191         DateFormatter dateFormat = new DateFormatter("yyyy-MM-dd");
1958 03 May 13 olle 192         // Set of objects with comparison for operation list export
1634 02 May 12 nicklas 193         Set<PersonalOpDate> opDates = new TreeSet<PersonalOpDate>();
1958 03 May 13 olle 194         // Set of objects with comparison for INCA export
1958 03 May 13 olle 195         Set<PersonalIncaExportData> incaExportData = new TreeSet<PersonalIncaExportData>();
1680 31 May 12 nicklas 196         Pattern caseNamePattern = Pattern.compile("\\..*"); // Pattern to strip suffix from case name (eg. everything after first '.')
1957 30 Apr 13 olle 197         if ("ExportMonthlyOpList".equals(cmd))
1634 02 May 12 nicklas 198         {
4717 28 Mar 18 nicklas 199           while (samples.hasNext())
1634 02 May 12 nicklas 200           {
4717 28 Mar 18 nicklas 201             Sample s = samples.next();
1957 30 Apr 13 olle 202             // Check the BiopsyType annotation
1957 30 Apr 13 olle 203             // We should only export those with 'SpecimenSurgery' or a missing value
1957 30 Apr 13 olle 204             String biopsyType = (String)Annotationtype.BIOPSY_TYPE.getAnnotationValue(dc, manager, s);
1957 30 Apr 13 olle 205             
1957 30 Apr 13 olle 206             if (biopsyType == null || biopsyType.equals("SpecimenSurgery"))
1634 02 May 12 nicklas 207             {
1957 30 Apr 13 olle 208               // The parent is the 'Case' and the grandparent is the 'Patient'
1957 30 Apr 13 olle 209               // Ignore samples that don't have parent items
1957 30 Apr 13 olle 210               BioMaterial theCase = s.getParent();
1957 30 Apr 13 olle 211               if (theCase instanceof Sample)
1634 02 May 12 nicklas 212               {
4496 10 May 17 nicklas 213                 // Ignore cases that doesn't have 'Yes'consent (but we allow missing consent since the
4496 10 May 17 nicklas 214                 // most likely case is the we will get a 'Yes' in the future)
4496 10 May 17 nicklas 215                 String consent = (String)Annotationtype.CONSENT.getAnnotationValue(dc, manager, theCase);
4496 10 May 17 nicklas 216                 if (consent == null || consent.equals("Yes"))
1957 30 Apr 13 olle 217                 {
4496 10 May 17 nicklas 218                   BioMaterial patient = ((Sample)theCase).getParent();
4496 10 May 17 nicklas 219                   if (patient instanceof BioSource)
1957 30 Apr 13 olle 220                   {
4496 10 May 17 nicklas 221                     // Get the personal number of the patient
4496 10 May 17 nicklas 222                     String pnr = (String)Annotationtype.PERSONAL_NUMBER.getAnnotationValue(dc, manager, patient);
4496 10 May 17 nicklas 223   
4496 10 May 17 nicklas 224                     if (pnr != null)
2250 25 Feb 14 olle 225                     {
4496 10 May 17 nicklas 226                       // Finally, we now have the information that should be exported
4496 10 May 17 nicklas 227                       Site site = Site.findByCaseName(s.getName());
4496 10 May 17 nicklas 228                       // Only include sites belonging to "RCC syd" (Regionalt Cancercentrum syd)
4496 10 May 17 nicklas 229                       if (site.isPartOfRCC_syd())
4496 10 May 17 nicklas 230                       {
4496 10 May 17 nicklas 231                         String laterality = (String)Annotationtype.LATERALITY.getAnnotationValue(dc, manager, theCase);
4496 10 May 17 nicklas 232                         String opDate = dateFormat.format(s.getCreationEvent().getEventDate());
4496 10 May 17 nicklas 233                         String subtype = exportSubtype ? s.getItemSubtype().getName() : null;
4496 10 May 17 nicklas 234                         String patientId = exportPatientId ? patient.getName() : null;
4496 10 May 17 nicklas 235                         String caseName = caseNamePattern.matcher(s.getName()).replaceFirst("");
4496 10 May 17 nicklas 236                         opDates.add(new PersonalOpDate(pnr, opDate, site, laterality, subtype, caseName, consent, patientId));
4496 10 May 17 nicklas 237                       }
2250 25 Feb 14 olle 238                     }
1957 30 Apr 13 olle 239                   }
1957 30 Apr 13 olle 240                 }
1957 30 Apr 13 olle 241               }
1957 30 Apr 13 olle 242             }
1957 30 Apr 13 olle 243           }
1957 30 Apr 13 olle 244         }
1957 30 Apr 13 olle 245         else if ("ExportINCA".equals(cmd))
1957 30 Apr 13 olle 246         {
2607 28 Aug 14 nicklas 247           
1957 30 Apr 13 olle 248           // Get item subtype constants for later use
1957 30 Apr 13 olle 249           ItemSubtype subtypeSpecimen = Subtype.SPECIMEN.load(dc);
1957 30 Apr 13 olle 250           ItemSubtype subtypeNoSpecimen = Subtype.NO_SPECIMEN.load(dc);
1957 30 Apr 13 olle 251           ItemSubtype subtypeBlood = Subtype.BLOOD.load(dc);
1957 30 Apr 13 olle 252
3904 29 Apr 16 nicklas 253           int count = 0;
4717 28 Mar 18 nicklas 254           while (samples.hasNext())
1957 30 Apr 13 olle 255           {
4717 28 Mar 18 nicklas 256             Sample s = samples.next();
3904 29 Apr 16 nicklas 257             if (count % 100 == 0 && progress != null)
3904 29 Apr 16 nicklas 258             {
4717 28 Mar 18 nicklas 259               progress.display(5 + (int)((90 * count) / totalCount), count + " of " + totalCount + " samples examined");
3904 29 Apr 16 nicklas 260             }
3904 29 Apr 16 nicklas 261             count++;
3904 29 Apr 16 nicklas 262             
1957 30 Apr 13 olle 263             // Find patient id
1957 30 Apr 13 olle 264             BioMaterial theCase = null;
1957 30 Apr 13 olle 265             BioMaterial patient = null;
4717 28 Mar 18 nicklas 266             String consent = null;
4717 28 Mar 18 nicklas 267             ItemSubtype sampleType = s.getItemSubtype();
4717 28 Mar 18 nicklas 268             if (subtypeBlood.equals(sampleType))
1957 30 Apr 13 olle 269             {
1957 30 Apr 13 olle 270               // The parent is the 'Patient' for blood samples and cases
1957 30 Apr 13 olle 271               patient = s.getParent();
4717 28 Mar 18 nicklas 272               // For blood samples, consent is coupled to the sample
4717 28 Mar 18 nicklas 273               consent = (String)Annotationtype.CONSENT.getAnnotationValue(dc, manager, s);
1957 30 Apr 13 olle 274             }
6510 03 Dec 21 nicklas 275             else if (subtypeSpecimen.equals(sampleType) || subtypeNoSpecimen.equals(sampleType))
1957 30 Apr 13 olle 276             {
1957 30 Apr 13 olle 277               // The parent is the 'Case' and the grandparent is the 'Patient' for specimens and no specimens
1957 30 Apr 13 olle 278               theCase = (MeasuredBioMaterial) s.getParent();
1957 30 Apr 13 olle 279               if (theCase != null && theCase instanceof Sample)
1957 30 Apr 13 olle 280               {
1957 30 Apr 13 olle 281                 patient = ((Sample)theCase).getParent();
4717 28 Mar 18 nicklas 282                 // For specimen and no specimen samples, consent is coupled to the case
4717 28 Mar 18 nicklas 283                 consent = (String)Annotationtype.CONSENT.getAnnotationValue(dc, manager, theCase);
1957 30 Apr 13 olle 284               }
1957 30 Apr 13 olle 285             }
1957 30 Apr 13 olle 286
1957 30 Apr 13 olle 287             if (patient instanceof BioSource)
1957 30 Apr 13 olle 288             {
1957 30 Apr 13 olle 289               // Get the personal number of the patient
1957 30 Apr 13 olle 290               String pnr = (String)Annotationtype.PERSONAL_NUMBER.getAnnotationValue(dc, manager, patient);
1957 30 Apr 13 olle 291
1957 30 Apr 13 olle 292               if (pnr != null)
1957 30 Apr 13 olle 293               {
4496 10 May 17 nicklas 294                 // Ignore cases that doesn't have 'Yes'consent (but we allow missing consent since the
4496 10 May 17 nicklas 295                 // most likely case is the we will get a 'Yes' in the future)
4496 10 May 17 nicklas 296                 if (consent == null || consent.equals("Yes"))
4717 28 Mar 18 nicklas 297                 {                  
4717 28 Mar 18 nicklas 298                   incaExportData.add(new PersonalIncaExportData(pnr));
1958 03 May 13 olle 299                 }
1957 30 Apr 13 olle 300               }
1957 30 Apr 13 olle 301             }
1957 30 Apr 13 olle 302           }
1634 02 May 12 nicklas 303         }
1957 30 Apr 13 olle 304
1957 30 Apr 13 olle 305         // Default settings for monthly operation list export
4717 28 Mar 18 nicklas 306         String filenamePrefix = "";
4717 28 Mar 18 nicklas 307         String tableHeader = "PersonalNr";
1674 30 May 12 nicklas 308         DateFormatter monthFormat = new DateFormatter(fullYear ? "yyyy-'all'" : "yyyy-MM");
1957 30 Apr 13 olle 309         String dateString = monthFormat.format(start);
1957 30 Apr 13 olle 310         if (allSamples)
1957 30 Apr 13 olle 311         {
1957 30 Apr 13 olle 312           // Set date string to period from 2010 to current month
1957 30 Apr 13 olle 313           Date today = new Date();
1957 30 Apr 13 olle 314           dateString = "2010-" + monthFormat.format(today);
1957 30 Apr 13 olle 315         }
1957 30 Apr 13 olle 316         if ("ExportINCA".equals(cmd))
1957 30 Apr 13 olle 317         {
1957 30 Apr 13 olle 318           filenamePrefix = "incaexport-";
1957 30 Apr 13 olle 319         }
4717 28 Mar 18 nicklas 320         else if ("ExportMonthlyOpList".equals(cmd))
4717 28 Mar 18 nicklas 321         {
4717 28 Mar 18 nicklas 322           filenamePrefix = "opdates-";
4717 28 Mar 18 nicklas 323           tableHeader += "\tScanBId\tOpDate\tLaterality\tSite";
4717 28 Mar 18 nicklas 324           if (exportSubtype) tableHeader += "\tSample";
4717 28 Mar 18 nicklas 325           if (exportSubtype) tableHeader += "\tBiopsyType";
4717 28 Mar 18 nicklas 326           if (exportPatientId) tableHeader += "\tPatientId";
4717 28 Mar 18 nicklas 327           tableHeader += "\tConsent";
4717 28 Mar 18 nicklas 328         }
1957 30 Apr 13 olle 329         // Write export file
1957 30 Apr 13 olle 330         resp.setHeader("Content-Disposition", "attachment; filename=" + filenamePrefix + dateString + ".tsv");
1634 02 May 12 nicklas 331         resp.setContentType("text/plain");
1634 02 May 12 nicklas 332         resp.setCharacterEncoding("UTF-8");
1634 02 May 12 nicklas 333         PrintWriter os = resp.getWriter();
4717 28 Mar 18 nicklas 334         os.write(tableHeader+"\n");
1741 22 Nov 12 nicklas 335
4717 28 Mar 18 nicklas 336         int numExported = 0;
1958 03 May 13 olle 337         if ("ExportMonthlyOpList".equals(cmd))
1634 02 May 12 nicklas 338         {
1958 03 May 13 olle 339           for (PersonalOpDate pop : opDates)
1958 03 May 13 olle 340           {
1958 03 May 13 olle 341             os.write(pop.toString());
1958 03 May 13 olle 342             os.write("\n");
1958 03 May 13 olle 343           }
4717 28 Mar 18 nicklas 344           numExported = opDates.size();
1634 02 May 12 nicklas 345         }
1958 03 May 13 olle 346         else if ("ExportINCA".equals(cmd))
1958 03 May 13 olle 347         {
1958 03 May 13 olle 348           for (PersonalIncaExportData pie : incaExportData)
1958 03 May 13 olle 349           {
1958 03 May 13 olle 350             os.write(pie.toString());
1958 03 May 13 olle 351             os.write("\n");
1958 03 May 13 olle 352           }
4717 28 Mar 18 nicklas 353           numExported = incaExportData.size();
1958 03 May 13 olle 354         }
1634 02 May 12 nicklas 355         
3904 29 Apr 16 nicklas 356         if (progress != null)
3904 29 Apr 16 nicklas 357         {
4717 28 Mar 18 nicklas 358           progress.display(100, "Export complete. " + totalCount + " samples examined, " + numExported + " entries exported.");
4717 28 Mar 18 nicklas 359           Thread.sleep(3000); // Allow the progress bar in the GUI to update
3904 29 Apr 16 nicklas 360         }
3904 29 Apr 16 nicklas 361         
1634 02 May 12 nicklas 362         os.flush();
1634 02 May 12 nicklas 363         os.close();
1634 02 May 12 nicklas 364       }
2206 31 Jan 14 olle 365       else if ("ExportMissingSampleDataSampleList".equals(cmd))
2206 31 Jan 14 olle 366       {
6336 16 Jun 21 nicklas 367         dc = sc.newDbControl(":Export missing sample data");
2607 28 Aug 14 nicklas 368         useJsonForError = Values.getBoolean(req.getParameter("preview"));
2206 31 Jan 14 olle 369
2206 31 Jan 14 olle 370         ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.PATIENT_CURATOR, ReggieRole.ADMINISTRATOR);
2206 31 Jan 14 olle 371
2607 28 Aug 14 nicklas 372         String sampleType = Values.getString(req.getParameter("stype"), "specimen");
2206 31 Jan 14 olle 373         // Default settings for missing sample data list export
2206 31 Jan 14 olle 374         String filenamePrefix = "missingsampledata-";
2206 31 Jan 14 olle 375         // Get sample type string to use in filename
2206 31 Jan 14 olle 376         String exportListSampleType = sampleType;
2206 31 Jan 14 olle 377         if (sampleType.equals("specimen") || sampleType.equals("nospecimen"))
2206 31 Jan 14 olle 378         {
2206 31 Jan 14 olle 379           exportListSampleType = "specimen_nospecimen";
2206 31 Jan 14 olle 380         }
2206 31 Jan 14 olle 381         String bloodSampleFilter = null;
2206 31 Jan 14 olle 382         String tableHeaderStart = "SampleName\tSubtype\tPersonalNo\tAllFirstNames\tFamilyName";
2210 03 Feb 14 olle 383         if (sampleType.equals("specimen") ||
2210 03 Feb 14 olle 384           sampleType.equals("nospecimen") ||
2210 03 Feb 14 olle 385           sampleType.equals("specimen_nospecimen"))
2206 31 Jan 14 olle 386         {
2206 31 Jan 14 olle 387           tableHeaderStart += "\tPAD\tLaterality\tSamplingDate\tRNALaterDate\tBiopsyType";
2206 31 Jan 14 olle 388         }
2206 31 Jan 14 olle 389         else if (sampleType.equals("blood"))
2206 31 Jan 14 olle 390         {
2206 31 Jan 14 olle 391           tableHeaderStart += "\tBloodSamplingDate\tBloodFreezerDate\tBloodSampleType";
2206 31 Jan 14 olle 392         }
2206 31 Jan 14 olle 393         DateFormatter dateFormat = new DateFormatter("yyyy-MM-dd");
2206 31 Jan 14 olle 394         // Set current date
2206 31 Jan 14 olle 395         Date today = new Date();
2206 31 Jan 14 olle 396         String dateString = dateFormat.format(today);
2206 31 Jan 14 olle 397         // Write export file
2206 31 Jan 14 olle 398         resp.setHeader("Content-Disposition", "attachment; filename=" + filenamePrefix + dateString + "-" + exportListSampleType + ".tsv");
2206 31 Jan 14 olle 399         resp.setContentType("text/plain");
2206 31 Jan 14 olle 400         resp.setCharacterEncoding("UTF-8");
2206 31 Jan 14 olle 401         PrintWriter os = resp.getWriter();
2206 31 Jan 14 olle 402         os.write(tableHeaderStart);
2206 31 Jan 14 olle 403         os.write("\n");
2206 31 Jan 14 olle 404         // Set of objects with comparison for missing sample data export
3914 02 May 16 nicklas 405         Set<MissingSampleDataExportData> missingSampleDataExportData = createMissingSampleDataExport(dc, sampleType, bloodSampleFilter, progress);
2206 31 Jan 14 olle 406         for (MissingSampleDataExportData msd : missingSampleDataExportData)
2206 31 Jan 14 olle 407         {
2206 31 Jan 14 olle 408           os.write(msd.toString());
2206 31 Jan 14 olle 409           os.write("\n");
2206 31 Jan 14 olle 410         }        
2206 31 Jan 14 olle 411         os.flush();
2206 31 Jan 14 olle 412         os.close();  
3914 02 May 16 nicklas 413         if (progress != null) progress.display(100, "Done");
2206 31 Jan 14 olle 414       }
2212 04 Feb 14 olle 415       else if ("ExportMissingConsentDataSampleList".equals(cmd))
2212 04 Feb 14 olle 416       {
6336 16 Jun 21 nicklas 417         dc = sc.newDbControl(":Export missing consent");
2607 28 Aug 14 nicklas 418         useJsonForError = Values.getBoolean(req.getParameter("preview"));
2212 04 Feb 14 olle 419
2212 04 Feb 14 olle 420         ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.PATIENT_CURATOR, ReggieRole.ADMINISTRATOR);
2212 04 Feb 14 olle 421
2212 04 Feb 14 olle 422         // Default settings for missing consent data list export
2212 04 Feb 14 olle 423         String filenamePrefix = "missingconsentdata-";
2212 04 Feb 14 olle 424         String tableHeaderStart = "SampleName\tSubtype\tPersonalNo\tAllFirstNames\tFamilyName\tConsentDate\tConsent";
2212 04 Feb 14 olle 425         DateFormatter dateFormat = new DateFormatter("yyyy-MM-dd");
2212 04 Feb 14 olle 426         // Set current date
2212 04 Feb 14 olle 427         Date today = new Date();
2212 04 Feb 14 olle 428         String dateString = dateFormat.format(today);
2212 04 Feb 14 olle 429         // Write export file
2212 04 Feb 14 olle 430         resp.setHeader("Content-Disposition", "attachment; filename=" + filenamePrefix + dateString + ".tsv");
2212 04 Feb 14 olle 431         resp.setContentType("text/plain");
2212 04 Feb 14 olle 432         resp.setCharacterEncoding("UTF-8");
2212 04 Feb 14 olle 433         PrintWriter os = resp.getWriter();
2212 04 Feb 14 olle 434         os.write(tableHeaderStart);
2212 04 Feb 14 olle 435         os.write("\n");
2212 04 Feb 14 olle 436         // Set of objects with comparison for missing sample data export
3914 02 May 16 nicklas 437         Set<MissingConsentDataExportData> missingConsentDataExportData = createMissingConsentDataExport(dc, progress);
2212 04 Feb 14 olle 438         for (MissingConsentDataExportData msd : missingConsentDataExportData)
2212 04 Feb 14 olle 439         {
2212 04 Feb 14 olle 440           os.write(msd.toString());
2212 04 Feb 14 olle 441           os.write("\n");
2212 04 Feb 14 olle 442         }        
2212 04 Feb 14 olle 443         os.flush();
2212 04 Feb 14 olle 444         os.close();  
2212 04 Feb 14 olle 445       }
4627 21 Nov 17 nicklas 446       else if ("DownloadMappedData".equals(cmd))
4627 21 Nov 17 nicklas 447       {
6336 16 Jun 21 nicklas 448         dc = sc.newDbControl(":Map external data to releases");
4627 21 Nov 17 nicklas 449         ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.PATIENT_CURATOR, ReggieRole.ADMINISTRATOR);
4627 21 Nov 17 nicklas 450
4627 21 Nov 17 nicklas 451         // Default settings for missing consent data list export
5332 20 Mar 19 nicklas 452         StaticCache cache = Application.getStaticCache();
4627 21 Nov 17 nicklas 453         String originalFilename = (String)sc.getSessionSetting("mapped-data-filename");
5332 20 Mar 19 nicklas 454         String tmpFilePath = getTmpFileCacheKey(sc, originalFilename);        
5332 20 Mar 19 nicklas 455         if (originalFilename == null || !cache.exists(tmpFilePath))
4627 21 Nov 17 nicklas 456         {
4627 21 Nov 17 nicklas 457           throw new FileNotFoundException(originalFilename);
4627 21 Nov 17 nicklas 458         }
4627 21 Nov 17 nicklas 459
4627 21 Nov 17 nicklas 460         String today = Reggie.CONVERTER_DATE_TO_STRING_WITH_SEPARATOR.convert(new Date());
4627 21 Nov 17 nicklas 461         int lastDot = originalFilename.lastIndexOf('.');
4627 21 Nov 17 nicklas 462         String filename = lastDot > 0 ? originalFilename.substring(0, lastDot) + "-" + today + originalFilename.substring(lastDot) : originalFilename + "-" + today;
4627 21 Nov 17 nicklas 463
4627 21 Nov 17 nicklas 464         OutputStream out = null;
4627 21 Nov 17 nicklas 465         InputStream in = null;
4627 21 Nov 17 nicklas 466         try
4627 21 Nov 17 nicklas 467         {
5332 20 Mar 19 nicklas 468           in = cache.read(tmpFilePath, 5);
5332 20 Mar 19 nicklas 469
5332 20 Mar 19 nicklas 470           Cipher c = CryptoUtil.createSessionCipher(sc, Cipher.DECRYPT_MODE, originalFilename);
5332 20 Mar 19 nicklas 471           in = new CipherInputStream(in, c);
5332 20 Mar 19 nicklas 472
4627 21 Nov 17 nicklas 473           resp.setHeader("Content-Disposition", "attachment; filename=" + filename);
4627 21 Nov 17 nicklas 474           resp.setContentType("text/plain");
4627 21 Nov 17 nicklas 475           resp.setCharacterEncoding("UTF-8");
4627 21 Nov 17 nicklas 476           out = resp.getOutputStream();
4627 21 Nov 17 nicklas 477           FileUtil.copy(in, out);
4627 21 Nov 17 nicklas 478         }
4627 21 Nov 17 nicklas 479         finally
4627 21 Nov 17 nicklas 480         {
4627 21 Nov 17 nicklas 481           FileUtil.close(in);
4627 21 Nov 17 nicklas 482           FileUtil.close(out);
4627 21 Nov 17 nicklas 483         }
4627 21 Nov 17 nicklas 484       }
1634 02 May 12 nicklas 485     }
1634 02 May 12 nicklas 486     catch (Throwable t)
1634 02 May 12 nicklas 487     {
1634 02 May 12 nicklas 488       t.printStackTrace();
2603 27 Aug 14 nicklas 489       if (useJsonForError)
2603 27 Aug 14 nicklas 490       {
2603 27 Aug 14 nicklas 491         JsonUtil.setJsonResponseHeaders(resp);
2603 27 Aug 14 nicklas 492         JSONObject json = new JSONObject();
2603 27 Aug 14 nicklas 493         json.put("status", "error");
2603 27 Aug 14 nicklas 494         json.put("message", t.getMessage());
2603 27 Aug 14 nicklas 495         json.put("stacktrace", ThrowableUtil.stackTraceToString(t));
2603 27 Aug 14 nicklas 496         json.writeJSONString(resp.getWriter());
2603 27 Aug 14 nicklas 497       }
2603 27 Aug 14 nicklas 498       else
2603 27 Aug 14 nicklas 499       {
2674 16 Sep 14 nicklas 500         resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, t.getClass().getName() + ": " + t.getMessage());
2603 27 Aug 14 nicklas 501       }
1634 02 May 12 nicklas 502     }
1634 02 May 12 nicklas 503     finally
1634 02 May 12 nicklas 504     {
1634 02 May 12 nicklas 505       if (dc != null) dc.close();
3905 29 Apr 16 nicklas 506       if (progressName != null && sc != null)
3904 29 Apr 16 nicklas 507       {
3904 29 Apr 16 nicklas 508         sc.setSessionSetting(progressName, null);
3904 29 Apr 16 nicklas 509       }
1634 02 May 12 nicklas 510     }
1634 02 May 12 nicklas 511     
1634 02 May 12 nicklas 512   }
1634 02 May 12 nicklas 513
4627 21 Nov 17 nicklas 514   @Override
4627 21 Nov 17 nicklas 515   protected void doPost(HttpServletRequest req, HttpServletResponse resp)
4627 21 Nov 17 nicklas 516     throws ServletException, IOException 
4627 21 Nov 17 nicklas 517   {
4627 21 Nov 17 nicklas 518     String cmd = req.getParameter("cmd");
4627 21 Nov 17 nicklas 519     JsonUtil.setJsonResponseHeaders(resp);
4627 21 Nov 17 nicklas 520     
4627 21 Nov 17 nicklas 521     JSONObject json = new JSONObject();
4627 21 Nov 17 nicklas 522     json.put("status", "ok");
4627 21 Nov 17 nicklas 523     
4627 21 Nov 17 nicklas 524     JSONArray jsonMessages = new JSONArray();
1958 03 May 13 olle 525
4627 21 Nov 17 nicklas 526     final SessionControl sc = Reggie.getSessionControl(req);
4627 21 Nov 17 nicklas 527     DbControl dc = null;
4627 21 Nov 17 nicklas 528     String progressId = "";
4627 21 Nov 17 nicklas 529     try
4627 21 Nov 17 nicklas 530     {
4627 21 Nov 17 nicklas 531       if ("MapDataToReleases".equals(cmd))
4627 21 Nov 17 nicklas 532       {
6336 16 Jun 21 nicklas 533         dc = sc.newDbControl(":Map external data to releases");
4627 21 Nov 17 nicklas 534
4627 21 Nov 17 nicklas 535         ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.PATIENT_CURATOR, ReggieRole.ADMINISTRATOR);
4627 21 Nov 17 nicklas 536         
6474 04 Nov 21 nicklas 537         String separator = Values.getString(req.getParameter("separator"), "tab");
5663 11 Oct 19 nicklas 538         String mapFrom = Values.getString(req.getParameter("mapFrom"), "PersonalNo");
5663 11 Oct 19 nicklas 539         boolean exportCaseId = Values.getBoolean(req.getParameter("exportCaseId"));
5663 11 Oct 19 nicklas 540         boolean exportSpecimenId = Values.getBoolean(req.getParameter("exportSpecimenId"));
5740 20 Nov 19 nicklas 541         boolean exportPad = Values.getBoolean(req.getParameter("exportPad"));
5663 11 Oct 19 nicklas 542         boolean sortOutput = Values.getBoolean(req.getParameter("sortOutput"));
5663 11 Oct 19 nicklas 543
6474 04 Nov 21 nicklas 544         String separatorChar = "\t";
6474 04 Nov 21 nicklas 545         if ("comma".equals(separator))
6474 04 Nov 21 nicklas 546         {
6474 04 Nov 21 nicklas 547           separatorChar = ",";
6474 04 Nov 21 nicklas 548         }
6474 04 Nov 21 nicklas 549         else if ("semicolon".equals(separator))
6474 04 Nov 21 nicklas 550         {
6474 04 Nov 21 nicklas 551           separatorChar = ";";
6474 04 Nov 21 nicklas 552         }
6474 04 Nov 21 nicklas 553         
5663 11 Oct 19 nicklas 554         SnapshotManager manager = new SnapshotManager();
5740 20 Nov 19 nicklas 555         List<OutputColumn> outColumns = new ArrayList<>();
5740 20 Nov 19 nicklas 556         PatientLoader loader = null;
5663 11 Oct 19 nicklas 557         if ("PatientId".equals(mapFrom))
5663 11 Oct 19 nicklas 558         {
5740 20 Nov 19 nicklas 559           loader = PatientLoader.fromPatientId(dc);
5740 20 Nov 19 nicklas 560           outColumns.add(new PatientToPersonalNumberConverter(dc, manager));
5740 20 Nov 19 nicklas 561           if (exportPad) outColumns.add(ReleaseIdToPadConverter.fromPatientId(dc, manager));
5663 11 Oct 19 nicklas 562         }
5663 11 Oct 19 nicklas 563         else if ("CaseId".equals(mapFrom))
5663 11 Oct 19 nicklas 564         {
5740 20 Nov 19 nicklas 565           loader = PatientLoader.fromCaseId(dc);
5740 20 Nov 19 nicklas 566           outColumns.add(new PatientToPersonalNumberConverter(dc, manager));
5740 20 Nov 19 nicklas 567           if (exportPad) outColumns.add(ReleaseIdToPadConverter.fromCaseId(dc, manager));
5663 11 Oct 19 nicklas 568         }
5663 11 Oct 19 nicklas 569         else if ("SpecimenId".equals(mapFrom))
5663 11 Oct 19 nicklas 570         {
5740 20 Nov 19 nicklas 571           loader = PatientLoader.fromSpecimenId(dc);
5740 20 Nov 19 nicklas 572           outColumns.add(new PatientToPersonalNumberConverter(dc, manager));
5740 20 Nov 19 nicklas 573           if (exportPad) outColumns.add(ReleaseIdToPadConverter.fromSpecimenId(dc, manager));
5663 11 Oct 19 nicklas 574         }
5740 20 Nov 19 nicklas 575         else if ("PAD".equals(mapFrom))
5740 20 Nov 19 nicklas 576         {
5740 20 Nov 19 nicklas 577           PatientLoaderFromPad padLoader = new PatientLoaderFromPad(dc);
5740 20 Nov 19 nicklas 578           loader = padLoader;
5740 20 Nov 19 nicklas 579           outColumns.add(new PatientToReleaseIdConverter());
5740 20 Nov 19 nicklas 580           if (exportCaseId) outColumns.add(padLoader.toCaseId());
5740 20 Nov 19 nicklas 581           if (exportSpecimenId) outColumns.add(padLoader.toSpecimenId());
5740 20 Nov 19 nicklas 582         }
5663 11 Oct 19 nicklas 583         else // "PersonalNo"
5663 11 Oct 19 nicklas 584         {
5740 20 Nov 19 nicklas 585           loader = PatientLoader.fromPersonalNumber(dc);
5740 20 Nov 19 nicklas 586           outColumns.add(new PatientToReleaseIdConverter());
5740 20 Nov 19 nicklas 587           if (exportCaseId) outColumns.add(new PatientToCaseReleaseIdConverter(dc));
5740 20 Nov 19 nicklas 588           if (exportSpecimenId) outColumns.add(new PatientToSpecimenReleaseIdConverter(dc));
5663 11 Oct 19 nicklas 589         }
5740 20 Nov 19 nicklas 590         
4627 21 Nov 17 nicklas 591
4627 21 Nov 17 nicklas 592         InputStream uploadIn = null;
4627 21 Nov 17 nicklas 593         BufferedReader uploadReader = null;
4627 21 Nov 17 nicklas 594         OutputStream tmpOut = null;
4627 21 Nov 17 nicklas 595         TableWriter tmpWriter = null;
5332 20 Mar 19 nicklas 596         
4627 21 Nov 17 nicklas 597         boolean mapCompleted = false;
4627 21 Nov 17 nicklas 598         SimpleProgressReporter progress = new SimpleProgressReporter(null);
4633 22 Nov 17 nicklas 599         progressId = "map-data-progress";
4633 22 Nov 17 nicklas 600         sc.setSessionSetting(progressId, progress);
4627 21 Nov 17 nicklas 601         try
4627 21 Nov 17 nicklas 602         {
4627 21 Nov 17 nicklas 603           FileUpload uploader = new FileUpload(req);
4627 21 Nov 17 nicklas 604           FileUploadProgress uploadProgress = uploader.getProgress();
4627 21 Nov 17 nicklas 605           UploadedFile file = uploader.next();
4627 21 Nov 17 nicklas 606           long totalBytes = uploadProgress.getTotalBytes();
4627 21 Nov 17 nicklas 607           
4627 21 Nov 17 nicklas 608           // Prepare for reading the uploaded file
4627 21 Nov 17 nicklas 609           uploadIn = file.getInputStream();
4627 21 Nov 17 nicklas 610           uploadReader = new BufferedReader(new InputStreamReader(uploadIn, "UTF-8"));
4627 21 Nov 17 nicklas 611         
5663 11 Oct 19 nicklas 612           // Read the header line, check that it has at least two columns and write the new header        
4627 21 Nov 17 nicklas 613           String header = uploadReader.readLine();
4627 21 Nov 17 nicklas 614           long parsedCharacters = header.length()+1;
6474 04 Nov 21 nicklas 615           String[] dataIn = header.split(separatorChar, 2);
6474 04 Nov 21 nicklas 616           if (dataIn.length == 2) outColumns.add(new RestOfData(dataIn[1]));
4627 21 Nov 17 nicklas 617         
5740 20 Nov 19 nicklas 618           int lastCol = outColumns.size();
6474 04 Nov 21 nicklas 619           Object[] headerOut = new Object[lastCol];
5740 20 Nov 19 nicklas 620           for (int colNo = 0; colNo < lastCol; colNo++)
5740 20 Nov 19 nicklas 621           {
5740 20 Nov 19 nicklas 622             headerOut[colNo] = outColumns.get(colNo).getHeader();
5740 20 Nov 19 nicklas 623           }
4627 21 Nov 17 nicklas 624         
4627 21 Nov 17 nicklas 625           int lineOut = 0;
4627 21 Nov 17 nicklas 626           int linesSkipped = 0;
5740 20 Nov 19 nicklas 627           InputLine inputLine = new InputLine();
5740 20 Nov 19 nicklas 628           List<Object[]> dataOut = new ArrayList<>();
4627 21 Nov 17 nicklas 629           
4627 21 Nov 17 nicklas 630           String data = uploadReader.readLine();
4627 21 Nov 17 nicklas 631           while (data != null)
4627 21 Nov 17 nicklas 632           {
4627 21 Nov 17 nicklas 633             parsedCharacters += data.length() + 1;
5740 20 Nov 19 nicklas 634             inputLine.lineNo++;
5740 20 Nov 19 nicklas 635             progress.display((int)(100*parsedCharacters / totalBytes), "Working... " + inputLine.lineNo + " lines parsed so far...");
4627 21 Nov 17 nicklas 636             
6474 04 Nov 21 nicklas 637             inputLine.cols = data.split(separatorChar, 2);
6474 04 Nov 21 nicklas 638             inputLine.fromId = Values.getStringOrNull(inputLine.cols[0]);
5740 20 Nov 19 nicklas 639             if (inputLine.fromId == null)
4627 21 Nov 17 nicklas 640             {
5740 20 Nov 19 nicklas 641               throw new IOException("On line " + inputLine.lineNo + ": " + loader.getMapFromFriendlyName() + " is missing");
4627 21 Nov 17 nicklas 642             }
5740 20 Nov 19 nicklas 643             
5740 20 Nov 19 nicklas 644             inputLine.patient = loader.convert(inputLine);
4627 21 Nov 17 nicklas 645   
5740 20 Nov 19 nicklas 646             if (inputLine.patient == null)
4627 21 Nov 17 nicklas 647             {
4627 21 Nov 17 nicklas 648               linesSkipped++;
4627 21 Nov 17 nicklas 649               if (linesSkipped > 100 && lineOut == 0)
4627 21 Nov 17 nicklas 650               {
5740 20 Nov 19 nicklas 651                 throw new IOException("On line " + inputLine.lineNo + ": No patients found after " + inputLine.lineNo + " lines. Is this the correct file?");
4627 21 Nov 17 nicklas 652               }
4627 21 Nov 17 nicklas 653             }
5331 20 Mar 19 nicklas 654             else
5331 20 Mar 19 nicklas 655             {
5663 11 Oct 19 nicklas 656               Object[] output = new Object[headerOut.length];
5740 20 Nov 19 nicklas 657               for (int colNo = 0; colNo < lastCol; colNo++)
5663 11 Oct 19 nicklas 658               {
5740 20 Nov 19 nicklas 659                 output[colNo] = outColumns.get(colNo).convert(inputLine);
5663 11 Oct 19 nicklas 660               }
5663 11 Oct 19 nicklas 661               dataOut.add(output);
4627 21 Nov 17 nicklas 662               lineOut++;
4627 21 Nov 17 nicklas 663             }
4627 21 Nov 17 nicklas 664             data = uploadReader.readLine();
4627 21 Nov 17 nicklas 665           }
4627 21 Nov 17 nicklas 666           
4627 21 Nov 17 nicklas 667           if (lineOut == 0)
4627 21 Nov 17 nicklas 668           {
5740 20 Nov 19 nicklas 669             throw new IOException("On line " + inputLine.lineNo + ": No patients found. Is this the correct file?");
4627 21 Nov 17 nicklas 670           }
5663 11 Oct 19 nicklas 671
5663 11 Oct 19 nicklas 672           if (sortOutput) Collections.sort(dataOut, new OrderByFirstColumn());
5663 11 Oct 19 nicklas 673           
5663 11 Oct 19 nicklas 674           // Prepare for writing to a temporary file
5663 11 Oct 19 nicklas 675           String outputFilePath = getTmpFileCacheKey(sc, file.getFilename());
5663 11 Oct 19 nicklas 676           Cipher cipher = CryptoUtil.createSessionCipher(sc, Cipher.ENCRYPT_MODE, file.getFilename());
5663 11 Oct 19 nicklas 677           tmpOut = new CipherOutputStream(Application.getStaticCache().write(outputFilePath, 5), cipher);
5663 11 Oct 19 nicklas 678           tmpWriter = new TableWriter(new OutputStreamWriter(tmpOut, "UTF-8"));
6474 04 Nov 21 nicklas 679           tmpWriter.setDataSeparator(separatorChar);
5663 11 Oct 19 nicklas 680           tmpWriter.tablePrintData(headerOut);
5663 11 Oct 19 nicklas 681           for (Object[] outLines : dataOut)
5663 11 Oct 19 nicklas 682           {
5663 11 Oct 19 nicklas 683             tmpWriter.tablePrintData(outLines);
5663 11 Oct 19 nicklas 684           }
4627 21 Nov 17 nicklas 685           tmpWriter.flush();
4627 21 Nov 17 nicklas 686           tmpOut.flush();
5740 20 Nov 19 nicklas 687           jsonMessages.add("Parsed " + inputLine.lineNo + " lines from input file");
4627 21 Nov 17 nicklas 688           jsonMessages.add("Wrote " + lineOut + " lines to output file");
4627 21 Nov 17 nicklas 689           if (linesSkipped > 0)
4627 21 Nov 17 nicklas 690           {
5331 20 Mar 19 nicklas 691             jsonMessages.add("Skipped " + linesSkipped + " lines from input file (no patient found)");
4627 21 Nov 17 nicklas 692           }
4627 21 Nov 17 nicklas 693           else
4627 21 Nov 17 nicklas 694           {
5663 11 Oct 19 nicklas 695             jsonMessages.add("A patient was found for all lines");
4627 21 Nov 17 nicklas 696           }
5740 20 Nov 19 nicklas 697           json.put("numLinesIn", inputLine.lineNo);
4627 21 Nov 17 nicklas 698           json.put("numLinesOut", lineOut);
4627 21 Nov 17 nicklas 699           json.put("numNotFound", linesSkipped);
4627 21 Nov 17 nicklas 700           sc.setSessionSetting("mapped-data-filename", file.getFilename());
4627 21 Nov 17 nicklas 701           mapCompleted = true;
4627 21 Nov 17 nicklas 702         }
4627 21 Nov 17 nicklas 703         finally
4627 21 Nov 17 nicklas 704         {
4627 21 Nov 17 nicklas 705           FileUtil.close(uploadReader);
4627 21 Nov 17 nicklas 706           FileUtil.close(uploadIn);
4627 21 Nov 17 nicklas 707           FileUtil.close(tmpWriter);
4627 21 Nov 17 nicklas 708           FileUtil.close(tmpOut);
4627 21 Nov 17 nicklas 709         }
4627 21 Nov 17 nicklas 710       }
4627 21 Nov 17 nicklas 711   
4627 21 Nov 17 nicklas 712       json.put("messages", jsonMessages);
4627 21 Nov 17 nicklas 713     }
4627 21 Nov 17 nicklas 714     catch (Throwable t)
4627 21 Nov 17 nicklas 715     {
4627 21 Nov 17 nicklas 716       t.printStackTrace();
4627 21 Nov 17 nicklas 717       json.clear();
4627 21 Nov 17 nicklas 718       json.put("status", "error");
4627 21 Nov 17 nicklas 719       json.put("message", t.getMessage());
4627 21 Nov 17 nicklas 720       json.put("stacktrace", ThrowableUtil.stackTraceToString(t));
4627 21 Nov 17 nicklas 721     }
4627 21 Nov 17 nicklas 722     finally
4627 21 Nov 17 nicklas 723     {
4627 21 Nov 17 nicklas 724       if (dc != null) dc.close();
4627 21 Nov 17 nicklas 725       if (sc != null) sc.setSessionSetting(progressId, null);
4627 21 Nov 17 nicklas 726       json.writeJSONString(resp.getWriter());
4627 21 Nov 17 nicklas 727     }    
4627 21 Nov 17 nicklas 728   }
4627 21 Nov 17 nicklas 729
5332 20 Mar 19 nicklas 730   /**
5332 20 Mar 19 nicklas 731     Get the cache key to use for storing the report.
5332 20 Mar 19 nicklas 732     The path is a MD5 value calculated from the current session 
5332 20 Mar 19 nicklas 733     and user id.
5332 20 Mar 19 nicklas 734   */
5332 20 Mar 19 nicklas 735   private String getTmpFileCacheKey(SessionControl sc, String filename)
5332 20 Mar 19 nicklas 736   {
5332 20 Mar 19 nicklas 737     return "/reggie/map-data/" + MD5.getHashString(sc.getId()+"-"+sc.getLoggedInUserId()+"-"+filename)+".tmp";
5332 20 Mar 19 nicklas 738   }
5332 20 Mar 19 nicklas 739
5332 20 Mar 19 nicklas 740   
3914 02 May 16 nicklas 741   private Set<MissingSampleDataExportData> createMissingSampleDataExport(DbControl dc, String sampleType, String bloodSampleFilter, ProgressReporter progress)
2206 31 Jan 14 olle 742       throws ServletException, IOException 
2206 31 Jan 14 olle 743   {
2206 31 Jan 14 olle 744     // Use stored annotation snapshots for performance reasons
2206 31 Jan 14 olle 745     SnapshotManager manager = new SnapshotManager();        
2206 31 Jan 14 olle 746     DateFormatter dateFormat = new DateFormatter("yyyy-MM-dd");
2206 31 Jan 14 olle 747
2206 31 Jan 14 olle 748     // Get item subtype constants for later use
2206 31 Jan 14 olle 749     ItemSubtype subtypeSpecimen = Subtype.SPECIMEN.load(dc);
2206 31 Jan 14 olle 750     ItemSubtype subtypeNoSpecimen = Subtype.NO_SPECIMEN.load(dc);
2206 31 Jan 14 olle 751     ItemSubtype subtypeBlood = Subtype.BLOOD.load(dc);
2206 31 Jan 14 olle 752     
2206 31 Jan 14 olle 753     boolean permissionDeniedForPatientName = false;
2206 31 Jan 14 olle 754     try
2206 31 Jan 14 olle 755     {
2206 31 Jan 14 olle 756       Annotationtype.ALL_FIRST_NAMES.load(dc);
2206 31 Jan 14 olle 757       Annotationtype.FAMILY_NAME.load(dc);
2206 31 Jan 14 olle 758     }
2206 31 Jan 14 olle 759     catch (RuntimeException ex)
2206 31 Jan 14 olle 760     {
2206 31 Jan 14 olle 761       permissionDeniedForPatientName = true;
2206 31 Jan 14 olle 762     }
2206 31 Jan 14 olle 763     boolean permissionDeniedForPad = false;
2206 31 Jan 14 olle 764     try
2206 31 Jan 14 olle 765     {
2206 31 Jan 14 olle 766       Annotationtype.PAD.load(dc);
2206 31 Jan 14 olle 767     }
2206 31 Jan 14 olle 768     catch (RuntimeException ex)
2206 31 Jan 14 olle 769     {
2206 31 Jan 14 olle 770       permissionDeniedForPad = true;
2206 31 Jan 14 olle 771     }
2206 31 Jan 14 olle 772     
2607 28 Aug 14 nicklas 773     
3914 02 May 16 nicklas 774     ItemQuery<Sample> sampleQuery = Sample.getQuery();
3914 02 May 16 nicklas 775     sampleQuery.joinPermanent(Hql.innerJoin(null, "creationEvent", "ce", true));
3914 02 May 16 nicklas 776     // Select what sample subtype(s) to include in database search 
3914 02 May 16 nicklas 777     if (sampleType.equals("specimen") ||
3914 02 May 16 nicklas 778       sampleType.equals("nospecimen") ||
3914 02 May 16 nicklas 779       sampleType.equals("specimen_nospecimen"))
3914 02 May 16 nicklas 780     {
6510 03 Dec 21 nicklas 781       // Include 'Specimen' and 'No specimen' items
3914 02 May 16 nicklas 782       sampleQuery.restrict(
3914 02 May 16 nicklas 783         Restrictions.or(
3914 02 May 16 nicklas 784           Subtype.SPECIMEN.restriction(dc, null),
6510 03 Dec 21 nicklas 785           Subtype.NO_SPECIMEN.restriction(dc, null)
3914 02 May 16 nicklas 786         ));
3914 02 May 16 nicklas 787       sampleQuery.join(Hql.innerJoin(null, "parent", "cse", true));
3914 02 May 16 nicklas 788       sampleQuery.join(Hql.innerJoin("cse", "parent", "pat", true));
3914 02 May 16 nicklas 789       if (!permissionDeniedForPad)
3914 02 May 16 nicklas 790       {
3914 02 May 16 nicklas 791         sampleQuery.join(Annotations.leftJoin(Annotationtype.PAD.get(dc), "pad"));
3914 02 May 16 nicklas 792       }
3914 02 May 16 nicklas 793       sampleQuery.join(Annotations.leftJoin(Annotationtype.LATERALITY.get(dc), "lat"));
3914 02 May 16 nicklas 794       sampleQuery.join(Annotations.leftJoin(Annotationtype.SAMPLING_DATETIME.get(dc), "smd"));
3914 02 May 16 nicklas 795       sampleQuery.join(Annotations.leftJoin(Annotationtype.RNALATER_DATETIME.get(dc), "rnd"));
3914 02 May 16 nicklas 796
3914 02 May 16 nicklas 797       if (!permissionDeniedForPatientName)
3914 02 May 16 nicklas 798       {
3914 02 May 16 nicklas 799         sampleQuery.join(Annotations.leftJoin("pat", Annotationtype.ALL_FIRST_NAMES.get(dc), "afn"));
3914 02 May 16 nicklas 800         sampleQuery.join(Annotations.leftJoin("pat", Annotationtype.FAMILY_NAME.get(dc), "fmn"));
3914 02 May 16 nicklas 801       }
3914 02 May 16 nicklas 802
3914 02 May 16 nicklas 803       sampleQuery.restrict(
3914 02 May 16 nicklas 804         Restrictions.nullSafeOr(
3914 02 May 16 nicklas 805           permissionDeniedForPad ? null : Restrictions.eq(Hql.alias("pad"), null),
3914 02 May 16 nicklas 806           Restrictions.eq(Hql.alias("lat"), null),
3914 02 May 16 nicklas 807           Restrictions.eq(Hql.alias("smd"), null),
3914 02 May 16 nicklas 808           Restrictions.and(
3914 02 May 16 nicklas 809             Restrictions.eq(Hql.alias("rnd"), null), 
3914 02 May 16 nicklas 810             Subtype.SPECIMEN.restriction(dc, null)),
3914 02 May 16 nicklas 811           permissionDeniedForPatientName ? null : Restrictions.eq(Hql.alias("afn"), null),
3914 02 May 16 nicklas 812           permissionDeniedForPatientName ? null : Restrictions.eq(Hql.alias("fmn"), null)
3914 02 May 16 nicklas 813         ));
3914 02 May 16 nicklas 814       
3914 02 May 16 nicklas 815     }
3914 02 May 16 nicklas 816     else if (sampleType.equals("blood"))
3914 02 May 16 nicklas 817     {
3914 02 May 16 nicklas 818       Subtype.BLOOD.addFilter(dc, sampleQuery);
3914 02 May 16 nicklas 819       sampleQuery.join(Hql.innerJoin(null, "parent", "pat", true));
3914 02 May 16 nicklas 820       sampleQuery.join(Annotations.leftJoin(Annotationtype.BLOOD_SAMPLING_DATETIME.get(dc), "smd"));
3914 02 May 16 nicklas 821       sampleQuery.join(Annotations.leftJoin(Annotationtype.BLOOD_FREEZER_DATETIME.get(dc), "frd"));
3914 02 May 16 nicklas 822       if (!permissionDeniedForPatientName)
3914 02 May 16 nicklas 823       {
3914 02 May 16 nicklas 824         sampleQuery.join(Annotations.leftJoin("pat", Annotationtype.ALL_FIRST_NAMES.get(dc), "afn"));
3914 02 May 16 nicklas 825         sampleQuery.join(Annotations.leftJoin("pat", Annotationtype.FAMILY_NAME.get(dc), "fmn"));
3914 02 May 16 nicklas 826       }
3914 02 May 16 nicklas 827       
3914 02 May 16 nicklas 828       sampleQuery.restrict(
3914 02 May 16 nicklas 829         Restrictions.nullSafeOr(
3914 02 May 16 nicklas 830           Restrictions.eq(Hql.alias("smd"), null),
3914 02 May 16 nicklas 831           Restrictions.eq(Hql.alias("frd"), null),
3914 02 May 16 nicklas 832           permissionDeniedForPatientName ? null : Restrictions.eq(Hql.alias("afn"), null),
3914 02 May 16 nicklas 833           permissionDeniedForPatientName ? null : Restrictions.eq(Hql.alias("fmn"), null)
3914 02 May 16 nicklas 834       ));
3914 02 May 16 nicklas 835     }
3914 02 May 16 nicklas 836     sampleQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
3914 02 May 16 nicklas 837     sampleQuery.order(Orders.asc(Hql.property("name")));
3914 02 May 16 nicklas 838     sampleQuery.order(Orders.asc(Hql.property("ce", "eventDate")));
3914 02 May 16 nicklas 839     sampleQuery.setCacheResult(true);
3914 02 May 16 nicklas 840     
3914 02 May 16 nicklas 841     if (progress != null) progress.display(1, "Loading samples...");
3914 02 May 16 nicklas 842     long totalCount = sampleQuery.count(dc);
3914 02 May 16 nicklas 843     int count = 0;
3914 02 May 16 nicklas 844     
2607 28 Aug 14 nicklas 845     // Set of objects with comparison for missing sample data export
2607 28 Aug 14 nicklas 846     Set<MissingSampleDataExportData> missingSampleDataExportData = new TreeSet<MissingSampleDataExportData>();
2607 28 Aug 14 nicklas 847
2206 31 Jan 14 olle 848     //
3914 02 May 16 nicklas 849     Iterator<Sample> it = sampleQuery.iterate(dc);
3914 02 May 16 nicklas 850     while (it.hasNext())
2206 31 Jan 14 olle 851     {
3914 02 May 16 nicklas 852       if (count % 100 == 0 && progress != null)
3914 02 May 16 nicklas 853             {
3914 02 May 16 nicklas 854         progress.display(5 + (int)((95 * count) / totalCount), 
3914 02 May 16 nicklas 855             "Processing " + Reggie.formatCount(count) + " of " + Reggie.formatCount(totalCount) + " items");
3914 02 May 16 nicklas 856             }
3914 02 May 16 nicklas 857       count++;
3914 02 May 16 nicklas 858       
3914 02 May 16 nicklas 859       Sample s = it.next();
2607 28 Aug 14 nicklas 860       ItemSubtype sampleSubtype = s.getItemSubtype();
2206 31 Jan 14 olle 861       String biopsyType = (String)Annotationtype.BIOPSY_TYPE.getAnnotationValue(dc, manager, s);
2206 31 Jan 14 olle 862       // If biopsy type should be included, exchange null values for explanatory text
2206 31 Jan 14 olle 863       if (biopsyType == null)
2206 31 Jan 14 olle 864       {
6510 03 Dec 21 nicklas 865         if (subtypeSpecimen.equals(sampleSubtype) || subtypeNoSpecimen.equals(sampleSubtype))
2206 31 Jan 14 olle 866         {
2607 28 Aug 14 nicklas 867           biopsyType = "default";
2206 31 Jan 14 olle 868         }
2607 28 Aug 14 nicklas 869         else if (subtypeBlood.equals(sampleSubtype))
2206 31 Jan 14 olle 870         {
2607 28 Aug 14 nicklas 871           biopsyType = "not_available";
2206 31 Jan 14 olle 872         }
2206 31 Jan 14 olle 873       }
2206 31 Jan 14 olle 874
2206 31 Jan 14 olle 875       // Initialize sample data
2206 31 Jan 14 olle 876       String pnr = null;
2206 31 Jan 14 olle 877       String allFirstNames = null;
2206 31 Jan 14 olle 878       String familyName = null;
2206 31 Jan 14 olle 879       String pad = null;
2206 31 Jan 14 olle 880       String laterality = null;
2206 31 Jan 14 olle 881       Date samplingDate = null;
2206 31 Jan 14 olle 882       Date rnaLaterDate = null;
2206 31 Jan 14 olle 883       Date bloodSamplingDate = null;
2206 31 Jan 14 olle 884       Date bloodFreezerDate = null;
2206 31 Jan 14 olle 885       String bloodSampleType = null;
2206 31 Jan 14 olle 886
2607 28 Aug 14 nicklas 887       if (!permissionDeniedForPatientName)
2206 31 Jan 14 olle 888       {
2607 28 Aug 14 nicklas 889         BioMaterial patient = null;
2607 28 Aug 14 nicklas 890         if (subtypeBlood.equals(sampleSubtype))
2206 31 Jan 14 olle 891         {
2607 28 Aug 14 nicklas 892           // The parent is the 'Patient' for blood samples and cases
2607 28 Aug 14 nicklas 893           patient = s.getParent();
2607 28 Aug 14 nicklas 894         }
6510 03 Dec 21 nicklas 895         else if (subtypeSpecimen.equals(sampleSubtype) || subtypeNoSpecimen.equals(sampleSubtype))
2607 28 Aug 14 nicklas 896         {
2607 28 Aug 14 nicklas 897           // The grandparent is the 'Patient' for specimens and no specimens
2607 28 Aug 14 nicklas 898           MeasuredBioMaterial parent = (MeasuredBioMaterial) s.getParent();
2607 28 Aug 14 nicklas 899           if (parent != null)
2607 28 Aug 14 nicklas 900           {
2607 28 Aug 14 nicklas 901             patient = parent.getParent();
2607 28 Aug 14 nicklas 902           }
2607 28 Aug 14 nicklas 903         }
2607 28 Aug 14 nicklas 904         if (patient != null)
2607 28 Aug 14 nicklas 905         {
2206 31 Jan 14 olle 906           // Get the personal number of the patient
2206 31 Jan 14 olle 907           pnr = (String)Annotationtype.PERSONAL_NUMBER.getAnnotationValue(dc, manager, patient);
2206 31 Jan 14 olle 908           // Get patient all first names
2206 31 Jan 14 olle 909           allFirstNames = (String) Annotationtype.ALL_FIRST_NAMES.getAnnotationValue(dc, manager, patient);
2206 31 Jan 14 olle 910           // Get patient family name
2206 31 Jan 14 olle 911           familyName = (String) Annotationtype.FAMILY_NAME.getAnnotationValue(dc, manager, patient);
2206 31 Jan 14 olle 912         }
2206 31 Jan 14 olle 913       }
6510 03 Dec 21 nicklas 914       if (sampleSubtype.equals(subtypeSpecimen))
2206 31 Jan 14 olle 915       {
2206 31 Jan 14 olle 916         // Get PAD reference
2206 31 Jan 14 olle 917         if (!permissionDeniedForPad)
2206 31 Jan 14 olle 918         {
2206 31 Jan 14 olle 919           pad = (String) Annotationtype.PAD.getAnnotationValue(dc, manager, s);
2206 31 Jan 14 olle 920         }
2206 31 Jan 14 olle 921         // Get laterality
2206 31 Jan 14 olle 922         laterality = (String) Annotationtype.LATERALITY.getAnnotationValue(dc, manager, s);
2206 31 Jan 14 olle 923         // Get sampling date
2206 31 Jan 14 olle 924         samplingDate = (Date) Annotationtype.SAMPLING_DATETIME.getAnnotationValue(dc, manager, s);
2206 31 Jan 14 olle 925         // Get RNALater date
2206 31 Jan 14 olle 926         rnaLaterDate = (Date) Annotationtype.RNALATER_DATETIME.getAnnotationValue(dc, manager, s);
2206 31 Jan 14 olle 927       }
2607 28 Aug 14 nicklas 928       else if (sampleSubtype.equals(subtypeNoSpecimen))
2206 31 Jan 14 olle 929       {
2206 31 Jan 14 olle 930         // Get PAD reference
2206 31 Jan 14 olle 931         if (!permissionDeniedForPad)
2206 31 Jan 14 olle 932         {
2206 31 Jan 14 olle 933           pad = (String) Annotationtype.PAD.getAnnotationValue(dc, manager, s);
2206 31 Jan 14 olle 934         }
2206 31 Jan 14 olle 935         // Get laterality
2206 31 Jan 14 olle 936         laterality = (String) Annotationtype.LATERALITY.getAnnotationValue(dc, manager, s);
2206 31 Jan 14 olle 937         // Get sampling date
2206 31 Jan 14 olle 938         samplingDate = (Date) Annotationtype.SAMPLING_DATETIME.getAnnotationValue(dc, manager, s);
2206 31 Jan 14 olle 939       }
2607 28 Aug 14 nicklas 940       else if (sampleSubtype.equals(subtypeBlood))
2206 31 Jan 14 olle 941       {
2206 31 Jan 14 olle 942         // Get blood sampling date
2206 31 Jan 14 olle 943         bloodSamplingDate = (Date) Annotationtype.BLOOD_SAMPLING_DATETIME.getAnnotationValue(dc, manager, s);
2206 31 Jan 14 olle 944         // Get blood freezer date
2206 31 Jan 14 olle 945         bloodFreezerDate = (Date) Annotationtype.BLOOD_FREEZER_DATETIME.getAnnotationValue(dc, manager, s);
2206 31 Jan 14 olle 946         // Get blood sample annotation
2206 31 Jan 14 olle 947         bloodSampleType = (String) Annotationtype.BLOOD_SAMPLE.getAnnotationValue(dc, manager, s);
2206 31 Jan 14 olle 948       }
2607 28 Aug 14 nicklas 949         
2607 28 Aug 14 nicklas 950       String samplingDateStr = samplingDate == null ? null : dateFormat.format(samplingDate);
2607 28 Aug 14 nicklas 951       String rnaLaterDateStr = rnaLaterDate == null ? null : dateFormat.format(rnaLaterDate);
2607 28 Aug 14 nicklas 952       String bloodSamplingDateStr = bloodSamplingDate == null ? null : dateFormat.format(bloodSamplingDate);
2607 28 Aug 14 nicklas 953       String bloodFreezerDateStr = bloodFreezerDate == null ? null : dateFormat.format(bloodFreezerDate);
2607 28 Aug 14 nicklas 954       missingSampleDataExportData.add(new MissingSampleDataExportData(s.getName(), sampleSubtype.getName(), pnr, allFirstNames, familyName, pad, laterality, samplingDateStr, rnaLaterDateStr, biopsyType, bloodSamplingDateStr, bloodFreezerDateStr, bloodSampleType));
2206 31 Jan 14 olle 955     }
2206 31 Jan 14 olle 956     return missingSampleDataExportData;
2206 31 Jan 14 olle 957   }
2206 31 Jan 14 olle 958
2607 28 Aug 14 nicklas 959
3914 02 May 16 nicklas 960   private Set<MissingConsentDataExportData> createMissingConsentDataExport(DbControl dc, ProgressReporter progress)
2212 04 Feb 14 olle 961       throws ServletException, IOException 
2212 04 Feb 14 olle 962   {
2212 04 Feb 14 olle 963     // Use stored annotation snapshots for performance reasons
2212 04 Feb 14 olle 964     SnapshotManager manager = new SnapshotManager();        
2212 04 Feb 14 olle 965     DateFormatter dateFormat = new DateFormatter("yyyy-MM-dd");
2212 04 Feb 14 olle 966
2212 04 Feb 14 olle 967     boolean permissionDeniedForPatientName = false;
2212 04 Feb 14 olle 968     try
2212 04 Feb 14 olle 969     {
2212 04 Feb 14 olle 970       Annotationtype.ALL_FIRST_NAMES.load(dc);
2212 04 Feb 14 olle 971       Annotationtype.FAMILY_NAME.load(dc);
2212 04 Feb 14 olle 972     }
2212 04 Feb 14 olle 973     catch (RuntimeException ex)
2212 04 Feb 14 olle 974     {
2212 04 Feb 14 olle 975       permissionDeniedForPatientName = true;
2212 04 Feb 14 olle 976     }
2212 04 Feb 14 olle 977     
3914 02 May 16 nicklas 978     ItemQuery<Sample> sampleQuery = Sample.getQuery();
3914 02 May 16 nicklas 979     sampleQuery.joinPermanent(Hql.innerJoin(null, "creationEvent", "ce", true));
3914 02 May 16 nicklas 980     // ...only include 'Case' or 'Blood' items
3914 02 May 16 nicklas 981     sampleQuery.restrict(
3914 02 May 16 nicklas 982       Restrictions.or(
3914 02 May 16 nicklas 983         Subtype.CASE.restriction(dc, null),
3914 02 May 16 nicklas 984         Subtype.BLOOD.restriction(dc, null)
3914 02 May 16 nicklas 985       ));
3914 02 May 16 nicklas 986     sampleQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
3914 02 May 16 nicklas 987     sampleQuery.order(Orders.asc(Hql.property("name")));
3914 02 May 16 nicklas 988     sampleQuery.order(Orders.asc(Hql.property("ce", "eventDate")));
3914 02 May 16 nicklas 989     
3914 02 May 16 nicklas 990     sampleQuery.join(Annotations.leftJoin(Annotationtype.CONSENT.get(dc), "cst"));
3914 02 May 16 nicklas 991     sampleQuery.join(Annotations.leftJoin(Annotationtype.CONSENT_DATE.get(dc), "csd"));
3914 02 May 16 nicklas 992     
3914 02 May 16 nicklas 993     sampleQuery.restrict(
3914 02 May 16 nicklas 994       Restrictions.or(
3914 02 May 16 nicklas 995         Restrictions.eq(Hql.alias("cst"), null),
3914 02 May 16 nicklas 996         Restrictions.eq(Hql.alias("csd"), null)
3914 02 May 16 nicklas 997       ));
3914 02 May 16 nicklas 998     
3914 02 May 16 nicklas 999     sampleQuery.setCacheResult(true);
3914 02 May 16 nicklas 1000     
3914 02 May 16 nicklas 1001     if (progress != null) progress.display(1, "Loading samples...");
3914 02 May 16 nicklas 1002     long totalCount = sampleQuery.count(dc);
3914 02 May 16 nicklas 1003     int count = 0;
3914 02 May 16 nicklas 1004
3914 02 May 16 nicklas 1005     Iterator<Sample> it = sampleQuery.iterate(dc);
3914 02 May 16 nicklas 1006     
3914 02 May 16 nicklas 1007     // Set of objects with comparison for missing sample data export
3914 02 May 16 nicklas 1008     Set<MissingConsentDataExportData> missingConsentDataExportData = new TreeSet<MissingConsentDataExportData>();
3914 02 May 16 nicklas 1009     while (it.hasNext())
2212 04 Feb 14 olle 1010     {
3914 02 May 16 nicklas 1011       if (count % 100 == 0 && progress != null)
3914 02 May 16 nicklas 1012             {
3914 02 May 16 nicklas 1013         progress.display(5 + (int)((95 * count) / totalCount), 
3914 02 May 16 nicklas 1014             "Processing " + Reggie.formatCount(count) + " of " + Reggie.formatCount(totalCount) + " items");
3914 02 May 16 nicklas 1015             }
3914 02 May 16 nicklas 1016       count++;
3914 02 May 16 nicklas 1017       
3914 02 May 16 nicklas 1018       Sample s = it.next();
2212 04 Feb 14 olle 1019       String consent = (String) Annotationtype.CONSENT.getAnnotationValue(dc, manager, s);
2212 04 Feb 14 olle 1020       Date consentDate = (Date) Annotationtype.CONSENT_DATE.getAnnotationValue(dc, manager, s);
2212 04 Feb 14 olle 1021
2605 27 Aug 14 nicklas 1022       // Find patient 
2605 27 Aug 14 nicklas 1023       BioMaterial patient = s.getParent();
2605 27 Aug 14 nicklas 1024
2212 04 Feb 14 olle 1025       // Initialize sample data
2212 04 Feb 14 olle 1026       String pnr = null;
2212 04 Feb 14 olle 1027       String allFirstNames = null;
2212 04 Feb 14 olle 1028       String familyName = null;
2212 04 Feb 14 olle 1029
2212 04 Feb 14 olle 1030       if (patient != null)
2212 04 Feb 14 olle 1031       {
2212 04 Feb 14 olle 1032         if (!permissionDeniedForPatientName)
2212 04 Feb 14 olle 1033         {
2212 04 Feb 14 olle 1034           // Get the personal number of the patient
2212 04 Feb 14 olle 1035           pnr = (String)Annotationtype.PERSONAL_NUMBER.getAnnotationValue(dc, manager, patient);
2212 04 Feb 14 olle 1036           // Get patient all first names
2212 04 Feb 14 olle 1037           allFirstNames = (String) Annotationtype.ALL_FIRST_NAMES.getAnnotationValue(dc, manager, patient);
2212 04 Feb 14 olle 1038           // Get patient family name
2212 04 Feb 14 olle 1039           familyName = (String) Annotationtype.FAMILY_NAME.getAnnotationValue(dc, manager, patient);
2212 04 Feb 14 olle 1040         }
2212 04 Feb 14 olle 1041       }
2605 27 Aug 14 nicklas 1042       
2605 27 Aug 14 nicklas 1043       String consentDateStr = consentDate == null ? null : dateFormat.format(consentDate);
2605 27 Aug 14 nicklas 1044       missingConsentDataExportData.add(new MissingConsentDataExportData(s.getName(), s.getItemSubtype().getName(), pnr, allFirstNames, familyName, consentDateStr, consent));
2212 04 Feb 14 olle 1045     }
3914 02 May 16 nicklas 1046     if (progress != null) progress.display(100, "Done");
2212 04 Feb 14 olle 1047     return missingConsentDataExportData;
2212 04 Feb 14 olle 1048   }
2212 04 Feb 14 olle 1049
2206 31 Jan 14 olle 1050   /**
1958 03 May 13 olle 1051    * Updates a hash map of patient numbers/samples with a new sample.
1958 03 May 13 olle 1052    * The sample is stored for the patient, if no previous sample
1958 03 May 13 olle 1053    * has been stored for the latter. If a sample has been stored,
1958 03 May 13 olle 1054    * a new specimen or no specimen will replace a blood sample,
1958 03 May 13 olle 1055    * and a blood sample with earlier sampling date will replace
1958 03 May 13 olle 1056    * a blood sample with a later one.
1958 03 May 13 olle 1057    * Used to find patients that only have blood samples, and
1958 03 May 13 olle 1058    * then find the earliest blood sample for the patient. 
1958 03 May 13 olle 1059    * 
1958 03 May 13 olle 1060    * @param dc DbControl The DcControl to use for database access
1958 03 May 13 olle 1061    * @param manager SnapshotManager Snapshot manager for annotations
1958 03 May 13 olle 1062    * @param patientNumberSampleHashMap HashMap<String, Sample> Hash map to update
1958 03 May 13 olle 1063    * @param patientNumber String Patient number of update sample
1958 03 May 13 olle 1064    * @param s Sample Update sample
1958 03 May 13 olle 1065    * @param laterality String Laterality string of update sample
1958 03 May 13 olle 1066    * @return HashMap<String, Sample> The (optionally) updated hash map
1958 03 May 13 olle 1067    */
1957 30 Apr 13 olle 1068   private HashMap<String, Sample> updatePatientNumberSampleHashMap(
1957 30 Apr 13 olle 1069       DbControl dc, SnapshotManager manager,
1957 30 Apr 13 olle 1070       HashMap<String, Sample> patientNumberSampleHashMap, String patientNumber,
1957 30 Apr 13 olle 1071       Sample s, String laterality)
1957 30 Apr 13 olle 1072   {
1957 30 Apr 13 olle 1073     // Get item subtype constants
1957 30 Apr 13 olle 1074     ItemSubtype subtypeSpecimen = Subtype.SPECIMEN.load(dc);
1957 30 Apr 13 olle 1075     ItemSubtype subtypeNoSpecimen = Subtype.NO_SPECIMEN.load(dc);
1957 30 Apr 13 olle 1076     ItemSubtype subtypeBlood = Subtype.BLOOD.load(dc);
1957 30 Apr 13 olle 1077     // Sample data retrieval
1957 30 Apr 13 olle 1078     Sample storedSample = null;
1957 30 Apr 13 olle 1079     ItemSubtype storedSampleSubtype = null;
1957 30 Apr 13 olle 1080     if (patientNumberSampleHashMap.containsKey(patientNumber))
1957 30 Apr 13 olle 1081     {
5415 09 May 19 nicklas 1082       storedSample = patientNumberSampleHashMap.get(patientNumber);
1957 30 Apr 13 olle 1083       storedSampleSubtype = storedSample.getItemSubtype();
1957 30 Apr 13 olle 1084     }
1957 30 Apr 13 olle 1085     // Update section
1957 30 Apr 13 olle 1086     if (storedSampleSubtype == null)
1957 30 Apr 13 olle 1087     {
1957 30 Apr 13 olle 1088       // Patient number not in hash map, store sample
1957 30 Apr 13 olle 1089       patientNumberSampleHashMap.put(patientNumber, s);
1957 30 Apr 13 olle 1090     }
1957 30 Apr 13 olle 1091     else if (storedSampleSubtype.equals(subtypeBlood))
1957 30 Apr 13 olle 1092     {
1957 30 Apr 13 olle 1093       // Replace stored entry if sample equals specimen or no specimen
1957 30 Apr 13 olle 1094       if (s.getItemSubtype().equals(subtypeSpecimen)
1957 30 Apr 13 olle 1095           || s.getItemSubtype().equals(subtypeNoSpecimen))
1957 30 Apr 13 olle 1096       {
1957 30 Apr 13 olle 1097         patientNumberSampleHashMap.put(patientNumber, s);
1957 30 Apr 13 olle 1098       }
1957 30 Apr 13 olle 1099       else if (s.getItemSubtype().equals(subtypeBlood))
1957 30 Apr 13 olle 1100       {
1957 30 Apr 13 olle 1101         // Store sample if blood sample with earlier date
2674 16 Sep 14 nicklas 1102         Date storedDate = storedSample.getCreationEvent().getEventDate();
2674 16 Sep 14 nicklas 1103         Date sampleDate = s.getCreationEvent().getEventDate();
2674 16 Sep 14 nicklas 1104         if (sampleDate != null && (storedDate == null ||  sampleDate.before(storedDate)))
1957 30 Apr 13 olle 1105         {
1957 30 Apr 13 olle 1106           patientNumberSampleHashMap.put(patientNumber, s);
1957 30 Apr 13 olle 1107         }
1957 30 Apr 13 olle 1108       }
1957 30 Apr 13 olle 1109     }
1957 30 Apr 13 olle 1110     return patientNumberSampleHashMap;
1957 30 Apr 13 olle 1111   }
1957 30 Apr 13 olle 1112
1957 30 Apr 13 olle 1113
1634 02 May 12 nicklas 1114   class PersonalOpDate
1634 02 May 12 nicklas 1115     implements Comparable<PersonalOpDate>
1634 02 May 12 nicklas 1116   {
1634 02 May 12 nicklas 1117     private final String pnr;
1634 02 May 12 nicklas 1118     private final String opDate;
1634 02 May 12 nicklas 1119     private final Site site;
1673 30 May 12 nicklas 1120     private final String laterality;
1673 30 May 12 nicklas 1121     private final String subtype;
1679 31 May 12 nicklas 1122     private final String caseName;
1721 24 Sep 12 nicklas 1123     private final String consent;
1740 22 Nov 12 nicklas 1124     private final String patientId;
1634 02 May 12 nicklas 1125     
1740 22 Nov 12 nicklas 1126     PersonalOpDate(String pnr, String opDate, Site site, String laterality, String subtype, String caseName, String consent, String patientId)
1634 02 May 12 nicklas 1127     {
1634 02 May 12 nicklas 1128       this.pnr = pnr;
1634 02 May 12 nicklas 1129       this.opDate = opDate;
1634 02 May 12 nicklas 1130       this.site = site;
1672 30 May 12 nicklas 1131       this.laterality = laterality;
1673 30 May 12 nicklas 1132       this.subtype = subtype;
1679 31 May 12 nicklas 1133       this.caseName = caseName;
1721 24 Sep 12 nicklas 1134       this.consent = consent;
1740 22 Nov 12 nicklas 1135       this.patientId = patientId;
1634 02 May 12 nicklas 1136     }
1634 02 May 12 nicklas 1137     
1634 02 May 12 nicklas 1138     @Override
1634 02 May 12 nicklas 1139     public String toString()
1634 02 May 12 nicklas 1140     {
1740 22 Nov 12 nicklas 1141       return pnr + "\t" + caseName + "\t" + opDate + 
1740 22 Nov 12 nicklas 1142           "\t" + (laterality == null ? "" : laterality) + 
1740 22 Nov 12 nicklas 1143           "\t" + site.getName() + 
1740 22 Nov 12 nicklas 1144           (subtype==null ? "" : "\t" + subtype) + 
1740 22 Nov 12 nicklas 1145           (patientId==null ? "" : "\t"+patientId)+
1740 22 Nov 12 nicklas 1146           "\t" + (consent == null ? "MISSING" : consent.toUpperCase());
1634 02 May 12 nicklas 1147     }
1634 02 May 12 nicklas 1148
1634 02 May 12 nicklas 1149     @Override
1634 02 May 12 nicklas 1150     public int hashCode() 
1634 02 May 12 nicklas 1151     {
1634 02 May 12 nicklas 1152       return pnr.hashCode() + opDate.hashCode();
1634 02 May 12 nicklas 1153     }
1634 02 May 12 nicklas 1154
1634 02 May 12 nicklas 1155     @Override
1634 02 May 12 nicklas 1156     public boolean equals(Object obj) 
1634 02 May 12 nicklas 1157     {
1634 02 May 12 nicklas 1158       if (obj == null) return false;
1634 02 May 12 nicklas 1159       if (this == obj) return true;
1634 02 May 12 nicklas 1160       
1634 02 May 12 nicklas 1161       if (obj.getClass() != this.getClass()) return false;
1634 02 May 12 nicklas 1162       PersonalOpDate o = (PersonalOpDate)obj;
1672 30 May 12 nicklas 1163       return EqualsHelper.equals(this.pnr, o.pnr) && 
1672 30 May 12 nicklas 1164           EqualsHelper.equals(this.opDate, o.opDate) && 
1672 30 May 12 nicklas 1165           EqualsHelper.equals(this.laterality, o.laterality);
1634 02 May 12 nicklas 1166     }
1634 02 May 12 nicklas 1167
1634 02 May 12 nicklas 1168     @Override
1634 02 May 12 nicklas 1169     public int compareTo(PersonalOpDate o)
1634 02 May 12 nicklas 1170     {
1672 30 May 12 nicklas 1171       int result = Reggie.nullSafeCompare(this.opDate, o.opDate);
1634 02 May 12 nicklas 1172       if (result == 0)
1634 02 May 12 nicklas 1173       {
1672 30 May 12 nicklas 1174         result =  Reggie.nullSafeCompare(this.pnr, o.pnr);
1672 30 May 12 nicklas 1175         if (result == 0)
1672 30 May 12 nicklas 1176         {
1672 30 May 12 nicklas 1177           result = Reggie.nullSafeCompare(this.laterality, o.laterality);
1672 30 May 12 nicklas 1178         }
1634 02 May 12 nicklas 1179       }
1634 02 May 12 nicklas 1180       return result;
1634 02 May 12 nicklas 1181     }
1634 02 May 12 nicklas 1182     
1634 02 May 12 nicklas 1183   }
1958 03 May 13 olle 1184
1958 03 May 13 olle 1185
1958 03 May 13 olle 1186   class PersonalIncaExportData
1958 03 May 13 olle 1187     implements Comparable<PersonalIncaExportData>
1958 03 May 13 olle 1188   {
1958 03 May 13 olle 1189     private final String pnr;
1958 03 May 13 olle 1190     
4717 28 Mar 18 nicklas 1191     PersonalIncaExportData(String pnr)
1958 03 May 13 olle 1192     {
1958 03 May 13 olle 1193       this.pnr = pnr;
1958 03 May 13 olle 1194     }
1958 03 May 13 olle 1195     
1958 03 May 13 olle 1196     @Override
1958 03 May 13 olle 1197     public String toString()
1958 03 May 13 olle 1198     {
4717 28 Mar 18 nicklas 1199       return pnr;
1958 03 May 13 olle 1200     }
1958 03 May 13 olle 1201
1958 03 May 13 olle 1202     @Override
1958 03 May 13 olle 1203     public int hashCode() 
1958 03 May 13 olle 1204     {
4717 28 Mar 18 nicklas 1205       return pnr.hashCode();
1958 03 May 13 olle 1206     }
1958 03 May 13 olle 1207
1958 03 May 13 olle 1208     @Override
1958 03 May 13 olle 1209     public boolean equals(Object obj) 
1958 03 May 13 olle 1210     {
1958 03 May 13 olle 1211       if (obj == null) return false;
1958 03 May 13 olle 1212       if (this == obj) return true;
1958 03 May 13 olle 1213       
1958 03 May 13 olle 1214       if (obj.getClass() != this.getClass()) return false;
1958 03 May 13 olle 1215       PersonalIncaExportData o = (PersonalIncaExportData)obj;
4717 28 Mar 18 nicklas 1216       return EqualsHelper.equals(this.pnr, o.pnr);
1958 03 May 13 olle 1217     }
1958 03 May 13 olle 1218
1958 03 May 13 olle 1219     @Override
1958 03 May 13 olle 1220     public int compareTo(PersonalIncaExportData o)
1958 03 May 13 olle 1221     {
4717 28 Mar 18 nicklas 1222       int result = Reggie.nullSafeCompare(this.pnr, o.pnr);
1958 03 May 13 olle 1223       return result;
1958 03 May 13 olle 1224     }
1958 03 May 13 olle 1225     
1958 03 May 13 olle 1226   }
1634 02 May 12 nicklas 1227   
2206 31 Jan 14 olle 1228   class MissingSampleDataExportData
2206 31 Jan 14 olle 1229     implements Comparable<MissingSampleDataExportData>
2206 31 Jan 14 olle 1230   {
2206 31 Jan 14 olle 1231     private final String sampleName;
2206 31 Jan 14 olle 1232     private final String subtype;
2206 31 Jan 14 olle 1233     private final String pnr;
2206 31 Jan 14 olle 1234     private final String patientAllFirstNames;
2206 31 Jan 14 olle 1235     private final String patientFamilyName;
2206 31 Jan 14 olle 1236     private final String padReference;
2206 31 Jan 14 olle 1237     private final String laterality;
2206 31 Jan 14 olle 1238     private final String samplingDate;
2206 31 Jan 14 olle 1239     private final String rnaLaterDate;
2206 31 Jan 14 olle 1240     private final String biopsyType;
2206 31 Jan 14 olle 1241     private final String bloodSamplingDate;
2206 31 Jan 14 olle 1242     private final String bloodFreezerDate;
2206 31 Jan 14 olle 1243     private final String bloodSampleType;
2206 31 Jan 14 olle 1244   
2206 31 Jan 14 olle 1245     MissingSampleDataExportData(String sampleName, String subtype, String pnr, String patientAllFirstNames, String patientFamilyName, String padReference, String laterality, String samplingDate, String rnaLaterDate, String biopsyType, String bloodSamplingDate, String bloodFreezerDate, String bloodSampleType)
2206 31 Jan 14 olle 1246     {
2206 31 Jan 14 olle 1247       this.sampleName = sampleName;
2206 31 Jan 14 olle 1248       this.subtype = subtype;
2206 31 Jan 14 olle 1249       this.pnr = pnr;
2206 31 Jan 14 olle 1250       this.patientAllFirstNames = patientAllFirstNames;
2206 31 Jan 14 olle 1251       this.patientFamilyName = patientFamilyName;
2206 31 Jan 14 olle 1252       this.padReference = padReference;
2206 31 Jan 14 olle 1253       this.laterality = laterality;
2206 31 Jan 14 olle 1254       this.samplingDate = samplingDate;
2206 31 Jan 14 olle 1255       this.rnaLaterDate = rnaLaterDate;
2206 31 Jan 14 olle 1256       this.biopsyType = biopsyType;
2206 31 Jan 14 olle 1257       this.bloodSamplingDate = bloodSamplingDate;
2206 31 Jan 14 olle 1258       this.bloodFreezerDate = bloodFreezerDate;
2206 31 Jan 14 olle 1259       this.bloodSampleType = bloodSampleType;
2206 31 Jan 14 olle 1260     }
2206 31 Jan 14 olle 1261   
2206 31 Jan 14 olle 1262     @Override
2206 31 Jan 14 olle 1263     public String toString()
2206 31 Jan 14 olle 1264     {
2206 31 Jan 14 olle 1265       String returnStr = sampleName +
2206 31 Jan 14 olle 1266           "\t" + subtype +
2206 31 Jan 14 olle 1267           "\t" + pnr +
2206 31 Jan 14 olle 1268           "\t" + patientAllFirstNames +
2206 31 Jan 14 olle 1269           "\t" + patientFamilyName;
6510 03 Dec 21 nicklas 1270       if (subtype != null && (subtype.equals("Specimen") || subtype.equals("NoSpecimen")))
2206 31 Jan 14 olle 1271       {
2206 31 Jan 14 olle 1272         returnStr += "\t" + padReference +
2206 31 Jan 14 olle 1273             "\t" + laterality + 
2206 31 Jan 14 olle 1274             "\t" + samplingDate +
2206 31 Jan 14 olle 1275             "\t" + rnaLaterDate +
2206 31 Jan 14 olle 1276             "\t" + biopsyType;
2206 31 Jan 14 olle 1277       }
2206 31 Jan 14 olle 1278       else if (subtype != null && subtype.equals("Blood"))
2206 31 Jan 14 olle 1279       {
2206 31 Jan 14 olle 1280         returnStr += "\t" + bloodSamplingDate +
2206 31 Jan 14 olle 1281             "\t" + bloodFreezerDate +
2206 31 Jan 14 olle 1282             "\t" + bloodSampleType;
2206 31 Jan 14 olle 1283       }
2206 31 Jan 14 olle 1284       return returnStr;
2206 31 Jan 14 olle 1285     }
2206 31 Jan 14 olle 1286
2206 31 Jan 14 olle 1287     @Override
2206 31 Jan 14 olle 1288     public int hashCode() 
2206 31 Jan 14 olle 1289     {
2206 31 Jan 14 olle 1290       return sampleName.hashCode() + subtype.hashCode();
2206 31 Jan 14 olle 1291     }
2206 31 Jan 14 olle 1292
2206 31 Jan 14 olle 1293     @Override
2206 31 Jan 14 olle 1294     public boolean equals(Object obj) 
2206 31 Jan 14 olle 1295     {
2206 31 Jan 14 olle 1296       if (obj == null) return false;
2206 31 Jan 14 olle 1297       if (this == obj) return true;
2206 31 Jan 14 olle 1298     
2206 31 Jan 14 olle 1299       if (obj.getClass() != this.getClass()) return false;
2206 31 Jan 14 olle 1300       MissingSampleDataExportData o = (MissingSampleDataExportData)obj;
2206 31 Jan 14 olle 1301       return EqualsHelper.equals(this.sampleName, o.sampleName) && 
2206 31 Jan 14 olle 1302           EqualsHelper.equals(this.subtype, o.subtype) && 
2206 31 Jan 14 olle 1303           EqualsHelper.equals(this.pnr, o.pnr) && 
2206 31 Jan 14 olle 1304           EqualsHelper.equals(this.patientAllFirstNames, o.patientAllFirstNames) &&
2206 31 Jan 14 olle 1305           EqualsHelper.equals(this.patientFamilyName, o.patientFamilyName) &&
2206 31 Jan 14 olle 1306           EqualsHelper.equals(this.padReference, o.padReference) &&
2206 31 Jan 14 olle 1307           EqualsHelper.equals(this.laterality, o.laterality) &&
2206 31 Jan 14 olle 1308           EqualsHelper.equals(this.samplingDate, o.samplingDate) &&
2206 31 Jan 14 olle 1309           EqualsHelper.equals(this.rnaLaterDate, o.rnaLaterDate) &&
2206 31 Jan 14 olle 1310           EqualsHelper.equals(this.biopsyType, o.biopsyType) &&
2206 31 Jan 14 olle 1311           EqualsHelper.equals(this.bloodSamplingDate, o.bloodSamplingDate) &&
2206 31 Jan 14 olle 1312           EqualsHelper.equals(this.bloodFreezerDate, o.bloodFreezerDate) &&
2206 31 Jan 14 olle 1313           EqualsHelper.equals(this.bloodSampleType, o.bloodSampleType);
2206 31 Jan 14 olle 1314     }
2206 31 Jan 14 olle 1315
2206 31 Jan 14 olle 1316     @Override
2206 31 Jan 14 olle 1317     public int compareTo(MissingSampleDataExportData o)
2206 31 Jan 14 olle 1318     {
2206 31 Jan 14 olle 1319       int result = Reggie.nullSafeCompare(this.sampleName, o.sampleName);
2206 31 Jan 14 olle 1320       if (result == 0)
2206 31 Jan 14 olle 1321       {
2206 31 Jan 14 olle 1322         result =  Reggie.nullSafeCompare(this.subtype, o.subtype);
2206 31 Jan 14 olle 1323         if (result == 0)
2206 31 Jan 14 olle 1324         {
2206 31 Jan 14 olle 1325           result =  Reggie.nullSafeCompare(this.pnr, o.pnr);
2206 31 Jan 14 olle 1326           if (result == 0)
2206 31 Jan 14 olle 1327           {
2206 31 Jan 14 olle 1328             result = Reggie.nullSafeCompare(this.patientAllFirstNames, o.patientAllFirstNames);
2206 31 Jan 14 olle 1329             if (result == 0)
2206 31 Jan 14 olle 1330             {
2206 31 Jan 14 olle 1331               result = Reggie.nullSafeCompare(this.patientFamilyName, o.patientFamilyName);
2206 31 Jan 14 olle 1332               if (result == 0)
2206 31 Jan 14 olle 1333               {
2206 31 Jan 14 olle 1334                 result = Reggie.nullSafeCompare(this.padReference, o.padReference);
2206 31 Jan 14 olle 1335                 if (result == 0)
2206 31 Jan 14 olle 1336                 {
2206 31 Jan 14 olle 1337                   result = Reggie.nullSafeCompare(this.laterality, o.laterality);
2206 31 Jan 14 olle 1338                   if (result == 0)
2206 31 Jan 14 olle 1339                   {
2206 31 Jan 14 olle 1340                     result = Reggie.nullSafeCompare(this.samplingDate, o.samplingDate);
2206 31 Jan 14 olle 1341                     if (result == 0)
2206 31 Jan 14 olle 1342                     {
2206 31 Jan 14 olle 1343                       result = Reggie.nullSafeCompare(this.rnaLaterDate, o.rnaLaterDate);
2206 31 Jan 14 olle 1344                       if (result == 0)
2206 31 Jan 14 olle 1345                       {
2206 31 Jan 14 olle 1346                         result = Reggie.nullSafeCompare(this.biopsyType, o.biopsyType);
2206 31 Jan 14 olle 1347                         if (result == 0)
2206 31 Jan 14 olle 1348                         {
2206 31 Jan 14 olle 1349                           result = Reggie.nullSafeCompare(this.bloodSamplingDate, o.bloodSamplingDate);
2206 31 Jan 14 olle 1350                           if (result == 0)
2206 31 Jan 14 olle 1351                           {
2206 31 Jan 14 olle 1352                             result = Reggie.nullSafeCompare(this.bloodFreezerDate, o.bloodFreezerDate);
2206 31 Jan 14 olle 1353                             if (result == 0)
2206 31 Jan 14 olle 1354                             {
2206 31 Jan 14 olle 1355                               result = Reggie.nullSafeCompare(this.bloodSampleType, o.bloodSampleType);
2206 31 Jan 14 olle 1356                             }
2206 31 Jan 14 olle 1357                           }
2206 31 Jan 14 olle 1358                         }
2206 31 Jan 14 olle 1359                       }
2206 31 Jan 14 olle 1360                     }
2206 31 Jan 14 olle 1361                   }
2206 31 Jan 14 olle 1362                 }
2206 31 Jan 14 olle 1363               }
2206 31 Jan 14 olle 1364             }
2206 31 Jan 14 olle 1365           }
2206 31 Jan 14 olle 1366         }
2206 31 Jan 14 olle 1367       }
2206 31 Jan 14 olle 1368       return result;
2206 31 Jan 14 olle 1369     }
2206 31 Jan 14 olle 1370   }
2206 31 Jan 14 olle 1371
2212 04 Feb 14 olle 1372   
2212 04 Feb 14 olle 1373   class MissingConsentDataExportData
2212 04 Feb 14 olle 1374     implements Comparable<MissingConsentDataExportData>
2212 04 Feb 14 olle 1375   {
2212 04 Feb 14 olle 1376     private final String sampleName;
2212 04 Feb 14 olle 1377     private final String subtype;
2212 04 Feb 14 olle 1378     private final String pnr;
2212 04 Feb 14 olle 1379     private final String patientAllFirstNames;
2212 04 Feb 14 olle 1380     private final String patientFamilyName;
2212 04 Feb 14 olle 1381     private final String consentDate;
2212 04 Feb 14 olle 1382     private final String consent;
2212 04 Feb 14 olle 1383
2212 04 Feb 14 olle 1384     MissingConsentDataExportData(String sampleName, String subtype, String pnr, String patientAllFirstNames, String patientFamilyName, String consentDate, String consent)
2212 04 Feb 14 olle 1385     {
2212 04 Feb 14 olle 1386       this.sampleName = sampleName;
2212 04 Feb 14 olle 1387       this.subtype = subtype;
2212 04 Feb 14 olle 1388       this.pnr = pnr;
2212 04 Feb 14 olle 1389       this.patientAllFirstNames = patientAllFirstNames;
2212 04 Feb 14 olle 1390       this.patientFamilyName = patientFamilyName;
2212 04 Feb 14 olle 1391       this.consentDate = consentDate;
2212 04 Feb 14 olle 1392       this.consent = consent;
2212 04 Feb 14 olle 1393     }
2212 04 Feb 14 olle 1394
2212 04 Feb 14 olle 1395     @Override
2212 04 Feb 14 olle 1396     public String toString()
2212 04 Feb 14 olle 1397     {
2212 04 Feb 14 olle 1398       String returnStr = sampleName +
2212 04 Feb 14 olle 1399           "\t" + subtype +
2212 04 Feb 14 olle 1400           "\t" + pnr +
2212 04 Feb 14 olle 1401           "\t" + patientAllFirstNames +
2212 04 Feb 14 olle 1402           "\t" + patientFamilyName +
2212 04 Feb 14 olle 1403           "\t" + consentDate +
2212 04 Feb 14 olle 1404           "\t" + consent;
2212 04 Feb 14 olle 1405       return returnStr;
2212 04 Feb 14 olle 1406     }
2212 04 Feb 14 olle 1407
2212 04 Feb 14 olle 1408     @Override
2212 04 Feb 14 olle 1409     public int hashCode() 
2212 04 Feb 14 olle 1410     {
2212 04 Feb 14 olle 1411       return sampleName.hashCode() + subtype.hashCode();
2212 04 Feb 14 olle 1412     }
2212 04 Feb 14 olle 1413
2212 04 Feb 14 olle 1414     @Override
2212 04 Feb 14 olle 1415     public boolean equals(Object obj) 
2212 04 Feb 14 olle 1416     {
2212 04 Feb 14 olle 1417       if (obj == null) return false;
2212 04 Feb 14 olle 1418       if (this == obj) return true;
2212 04 Feb 14 olle 1419
2212 04 Feb 14 olle 1420       if (obj.getClass() != this.getClass()) return false;
2212 04 Feb 14 olle 1421       MissingConsentDataExportData o = (MissingConsentDataExportData)obj;
2212 04 Feb 14 olle 1422       return EqualsHelper.equals(this.sampleName, o.sampleName) && 
2212 04 Feb 14 olle 1423           EqualsHelper.equals(this.subtype, o.subtype) && 
2212 04 Feb 14 olle 1424           EqualsHelper.equals(this.pnr, o.pnr) && 
2212 04 Feb 14 olle 1425           EqualsHelper.equals(this.consentDate, o.consentDate) &&
2212 04 Feb 14 olle 1426           EqualsHelper.equals(this.consent, o.consent);
2212 04 Feb 14 olle 1427     }
2212 04 Feb 14 olle 1428
2212 04 Feb 14 olle 1429     @Override
2212 04 Feb 14 olle 1430     public int compareTo(MissingConsentDataExportData o)
2212 04 Feb 14 olle 1431     {
2212 04 Feb 14 olle 1432       int result = Reggie.nullSafeCompare(this.sampleName, o.sampleName);
2212 04 Feb 14 olle 1433       if (result == 0)
2212 04 Feb 14 olle 1434       {
2212 04 Feb 14 olle 1435         result =  Reggie.nullSafeCompare(this.subtype, o.subtype);
2212 04 Feb 14 olle 1436         if (result == 0)
2212 04 Feb 14 olle 1437         {
2212 04 Feb 14 olle 1438           result =  Reggie.nullSafeCompare(this.pnr, o.pnr);
2212 04 Feb 14 olle 1439           if (result == 0)
2212 04 Feb 14 olle 1440           {
2212 04 Feb 14 olle 1441             result = Reggie.nullSafeCompare(this.patientAllFirstNames, o.patientAllFirstNames);
2212 04 Feb 14 olle 1442             if (result == 0)
2212 04 Feb 14 olle 1443             {
2212 04 Feb 14 olle 1444               result = Reggie.nullSafeCompare(this.patientFamilyName, o.patientFamilyName);
2212 04 Feb 14 olle 1445               if (result == 0)
2212 04 Feb 14 olle 1446               {
2212 04 Feb 14 olle 1447                 result = Reggie.nullSafeCompare(this.consentDate, o.consentDate);
2212 04 Feb 14 olle 1448                 if (result == 0)
2212 04 Feb 14 olle 1449                 {
2212 04 Feb 14 olle 1450                   result = Reggie.nullSafeCompare(this.consent, o.consent);
2212 04 Feb 14 olle 1451                 }
2212 04 Feb 14 olle 1452               }
2212 04 Feb 14 olle 1453             }
2212 04 Feb 14 olle 1454           }
2212 04 Feb 14 olle 1455         }
2212 04 Feb 14 olle 1456       }
2212 04 Feb 14 olle 1457       return result;
2212 04 Feb 14 olle 1458     }
2212 04 Feb 14 olle 1459   }
2212 04 Feb 14 olle 1460   
4627 21 Nov 17 nicklas 1461   static class RemoveTempFile
4627 21 Nov 17 nicklas 1462     extends TimerTask
4627 21 Nov 17 nicklas 1463   {
4627 21 Nov 17 nicklas 1464     
4627 21 Nov 17 nicklas 1465     private final java.io.File file;
4627 21 Nov 17 nicklas 1466     RemoveTempFile(java.io.File file)
4627 21 Nov 17 nicklas 1467     {
4627 21 Nov 17 nicklas 1468       this.file = file;
4627 21 Nov 17 nicklas 1469     }
4627 21 Nov 17 nicklas 1470     
4627 21 Nov 17 nicklas 1471     @Override
4627 21 Nov 17 nicklas 1472     public void run()
4627 21 Nov 17 nicklas 1473     {
4627 21 Nov 17 nicklas 1474       file.delete();
4627 21 Nov 17 nicklas 1475     }
4627 21 Nov 17 nicklas 1476   }
5663 11 Oct 19 nicklas 1477   
5663 11 Oct 19 nicklas 1478   /**
5740 20 Nov 19 nicklas 1479     Represents a line from the input file.
5740 20 Nov 19 nicklas 1480     TODO -- add more data here ?
5740 20 Nov 19 nicklas 1481   */
5740 20 Nov 19 nicklas 1482   static class InputLine
5740 20 Nov 19 nicklas 1483   {
5740 20 Nov 19 nicklas 1484     int lineNo;
6474 04 Nov 21 nicklas 1485     String[] cols;
5740 20 Nov 19 nicklas 1486     String fromId;
5740 20 Nov 19 nicklas 1487     BioSource patient;
5740 20 Nov 19 nicklas 1488   }
5740 20 Nov 19 nicklas 1489   
5740 20 Nov 19 nicklas 1490   /**
5740 20 Nov 19 nicklas 1491     Implementations need to take an input line and
5740 20 Nov 19 nicklas 1492     find a single patient for that line.
5740 20 Nov 19 nicklas 1493   */
5740 20 Nov 19 nicklas 1494   static abstract class PatientLoader
5740 20 Nov 19 nicklas 1495     implements ValueConverter<InputLine, BioSource>
5740 20 Nov 19 nicklas 1496   {
5740 20 Nov 19 nicklas 1497     static PatientLoader fromPersonalNumber(DbControl dc)
5740 20 Nov 19 nicklas 1498     {
5740 20 Nov 19 nicklas 1499       ItemQuery<BioSource> query = BioSource.getQuery();
5740 20 Nov 19 nicklas 1500       query.join(Annotations.innerJoin(null, Annotationtype.PERSONAL_NUMBER.load(dc), "pnr"));
5740 20 Nov 19 nicklas 1501       query.restrict(Restrictions.eq(Hql.alias("pnr"), Expressions.parameter("fromId")));
5740 20 Nov 19 nicklas 1502       return new PatientLoaderByQuery(dc, query, "personal number");
5740 20 Nov 19 nicklas 1503     }
5740 20 Nov 19 nicklas 1504     
5740 20 Nov 19 nicklas 1505     static PatientLoader fromPatientId(DbControl dc)
5740 20 Nov 19 nicklas 1506     {
5740 20 Nov 19 nicklas 1507       ItemQuery<BioSource> query = BioSource.getQuery();
5740 20 Nov 19 nicklas 1508       query.restrict(Restrictions.eq(Hql.property("externalId"), Expressions.parameter("fromId")));
5740 20 Nov 19 nicklas 1509       return new PatientLoaderByQuery(dc, query, "patient release ID");
5740 20 Nov 19 nicklas 1510     }
5740 20 Nov 19 nicklas 1511     
5740 20 Nov 19 nicklas 1512     static PatientLoader fromCaseId(DbControl dc)
5740 20 Nov 19 nicklas 1513     {
5740 20 Nov 19 nicklas 1514       ItemQuery<BioSource> query = BioSource.getQuery();
5740 20 Nov 19 nicklas 1515       query.join(Hql.innerJoin("childCreationEvents", "cce"));
5740 20 Nov 19 nicklas 1516       query.join(Hql.innerJoin("cce", "event", "evt"));
5740 20 Nov 19 nicklas 1517       query.join(Hql.innerJoin("evt", "bioMaterial", "cse")); // 'cse' should now reference a case
5740 20 Nov 19 nicklas 1518       query.restrict(Restrictions.eq(Hql.property("cse", "externalId"), Expressions.parameter("fromId")));
5740 20 Nov 19 nicklas 1519       return new PatientLoaderByQuery(dc, query, "case release ID");
5740 20 Nov 19 nicklas 1520     }
5740 20 Nov 19 nicklas 1521     
5740 20 Nov 19 nicklas 1522     static PatientLoader fromSpecimenId(DbControl dc)
5740 20 Nov 19 nicklas 1523     {
5740 20 Nov 19 nicklas 1524       ItemQuery<BioSource> query = BioSource.getQuery();
5740 20 Nov 19 nicklas 1525       query.join(Hql.innerJoin("childCreationEvents", "cce"));
5740 20 Nov 19 nicklas 1526       query.join(Hql.innerJoin("cce", "event", "evt"));
5740 20 Nov 19 nicklas 1527       query.join(Hql.innerJoin("evt", "bioMaterial", "cse")); // 'cse' should now reference a case
5740 20 Nov 19 nicklas 1528       query.join(Hql.innerJoin("cse", "childCreationEvents", "cce2"));
5740 20 Nov 19 nicklas 1529       query.join(Hql.innerJoin("cce2", "event", "evt2"));
5740 20 Nov 19 nicklas 1530       query.join(Hql.innerJoin("evt2", "bioMaterial", "spm")); // 'spm' should now reference a specimen/nospecimen
5740 20 Nov 19 nicklas 1531       query.restrict(Restrictions.eq(Hql.property("spm", "externalId"), Expressions.parameter("fromId")));
5740 20 Nov 19 nicklas 1532       return new PatientLoaderByQuery(dc, query, "specimen release ID");
5740 20 Nov 19 nicklas 1533     }
5740 20 Nov 19 nicklas 1534     
5740 20 Nov 19 nicklas 1535     final String mapFromFriendlyName;
5740 20 Nov 19 nicklas 1536     final DbControl dc;
5740 20 Nov 19 nicklas 1537
5740 20 Nov 19 nicklas 1538     PatientLoader(DbControl dc, String mapFromFriendlyName)
5740 20 Nov 19 nicklas 1539     {
5740 20 Nov 19 nicklas 1540       this.dc = dc;
5740 20 Nov 19 nicklas 1541       this.mapFromFriendlyName = mapFromFriendlyName;
5740 20 Nov 19 nicklas 1542     }
5740 20 Nov 19 nicklas 1543     
5740 20 Nov 19 nicklas 1544     public String getMapFromFriendlyName()
5740 20 Nov 19 nicklas 1545     {
5740 20 Nov 19 nicklas 1546       return mapFromFriendlyName;
5740 20 Nov 19 nicklas 1547     }
5740 20 Nov 19 nicklas 1548   }
5740 20 Nov 19 nicklas 1549   
5740 20 Nov 19 nicklas 1550   /**
5740 20 Nov 19 nicklas 1551     Patient loader implementation that can find the patient by executing a
5740 20 Nov 19 nicklas 1552     query using the source id as a parameter.
5740 20 Nov 19 nicklas 1553   */
5740 20 Nov 19 nicklas 1554   static class PatientLoaderByQuery
5740 20 Nov 19 nicklas 1555     extends PatientLoader
5740 20 Nov 19 nicklas 1556   {
5740 20 Nov 19 nicklas 1557     
5740 20 Nov 19 nicklas 1558     private final ItemQuery<BioSource> patientQuery;
5740 20 Nov 19 nicklas 1559     
5740 20 Nov 19 nicklas 1560     PatientLoaderByQuery(DbControl dc, ItemQuery<BioSource> patientQuery, String mapFromFriendlyName)
5740 20 Nov 19 nicklas 1561     {
5740 20 Nov 19 nicklas 1562       super(dc, mapFromFriendlyName);
5740 20 Nov 19 nicklas 1563       this.patientQuery = patientQuery;
5740 20 Nov 19 nicklas 1564       Subtype.PATIENT.addFilter(dc, patientQuery);
5740 20 Nov 19 nicklas 1565       patientQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
5740 20 Nov 19 nicklas 1566     }
5740 20 Nov 19 nicklas 1567     
5740 20 Nov 19 nicklas 1568     @Override
5740 20 Nov 19 nicklas 1569     public BioSource convert(InputLine ctx) 
5740 20 Nov 19 nicklas 1570     {
5740 20 Nov 19 nicklas 1571       patientQuery.setParameter("fromId", ctx.fromId, Type.STRING);
5740 20 Nov 19 nicklas 1572       List<BioSource> patients = patientQuery.list(dc);
5740 20 Nov 19 nicklas 1573       if (patients.size() > 1)
5740 20 Nov 19 nicklas 1574       {
5740 20 Nov 19 nicklas 1575         throw new RuntimeException("On line " + ctx.lineNo + ": Found " + patients.size() + " patients with same " + mapFromFriendlyName + ": " + ctx.fromId);
5740 20 Nov 19 nicklas 1576       }
5740 20 Nov 19 nicklas 1577       return patients.size() == 0 ? null : patients.get(0);
5740 20 Nov 19 nicklas 1578     }
5740 20 Nov 19 nicklas 1579   }
5740 20 Nov 19 nicklas 1580   
5740 20 Nov 19 nicklas 1581   /**
5740 20 Nov 19 nicklas 1582     Patient loader implementation when the source value is a PAD value. This implementation
5740 20 Nov 19 nicklas 1583     is used instead of the PatientLoaderByQuery for improved performance when 
5740 20 Nov 19 nicklas 1584     output columns for case and/or specimen release ID are required. The implementation
5740 20 Nov 19 nicklas 1585     executes an initial query to find the specimen item(s) with the given PAD and then
5740 20 Nov 19 nicklas 1586     uses the specimen to find other items. This avoids executing the slow query against 
5740 20 Nov 19 nicklas 1587     the PAD annotation more than once.
5740 20 Nov 19 nicklas 1588   */
5740 20 Nov 19 nicklas 1589   static class PatientLoaderFromPad
5740 20 Nov 19 nicklas 1590     extends PatientLoader
5740 20 Nov 19 nicklas 1591   {
5740 20 Nov 19 nicklas 1592     
5740 20 Nov 19 nicklas 1593     private final ItemQuery<Sample> specimenQuery;
5740 20 Nov 19 nicklas 1594     private final ItemQuery<BioSource> patientQuery;
5740 20 Nov 19 nicklas 1595     private List<Integer> currentSpecimen;
5740 20 Nov 19 nicklas 1596
5740 20 Nov 19 nicklas 1597     public PatientLoaderFromPad(DbControl dc)
5740 20 Nov 19 nicklas 1598     {
5740 20 Nov 19 nicklas 1599       super(dc, "PAD");
5740 20 Nov 19 nicklas 1600       
5740 20 Nov 19 nicklas 1601       specimenQuery = Sample.getQuery();
5740 20 Nov 19 nicklas 1602       specimenQuery.restrict(
5740 20 Nov 19 nicklas 1603         Restrictions.or(
5740 20 Nov 19 nicklas 1604           Subtype.SPECIMEN.restriction(dc, null),
6510 03 Dec 21 nicklas 1605           Subtype.NO_SPECIMEN.restriction(dc, null)
5740 20 Nov 19 nicklas 1606         ));
5740 20 Nov 19 nicklas 1607       specimenQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
5740 20 Nov 19 nicklas 1608       specimenQuery.join(Annotations.innerJoin(null, Annotationtype.PAD.load(dc), "pad"));
5740 20 Nov 19 nicklas 1609       specimenQuery.restrict(Restrictions.eq(Hql.alias("pad"), Expressions.parameter("fromId")));
5740 20 Nov 19 nicklas 1610       
5740 20 Nov 19 nicklas 1611       patientQuery = BioSource.getQuery();
5740 20 Nov 19 nicklas 1612       Subtype.PATIENT.addFilter(dc, patientQuery);
5740 20 Nov 19 nicklas 1613       patientQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
5740 20 Nov 19 nicklas 1614       patientQuery.join(Hql.innerJoin("childCreationEvents", "cce"));
5740 20 Nov 19 nicklas 1615       patientQuery.join(Hql.innerJoin("cce", "event", "evt"));
5740 20 Nov 19 nicklas 1616       patientQuery.join(Hql.innerJoin("evt", "bioMaterial", "cse")); // 'cse' should now reference a case
5740 20 Nov 19 nicklas 1617       patientQuery.join(Hql.innerJoin("cse", "childCreationEvents", "cce2"));
5740 20 Nov 19 nicklas 1618       patientQuery.join(Hql.innerJoin("cce2", "event", "evt2"));
5740 20 Nov 19 nicklas 1619       patientQuery.join(Hql.innerJoin("evt2", "bioMaterial", "spm")); // 'spm' should now reference a specimen/nospecimen
5740 20 Nov 19 nicklas 1620       patientQuery.restrict(Restrictions.in(Hql.alias("spm"), Expressions.parameter("specimen")));
5740 20 Nov 19 nicklas 1621       patientQuery.setDistinct(true);
5740 20 Nov 19 nicklas 1622     }
5740 20 Nov 19 nicklas 1623     
5740 20 Nov 19 nicklas 1624     @Override
5740 20 Nov 19 nicklas 1625     public String getMapFromFriendlyName()
5740 20 Nov 19 nicklas 1626     {
5740 20 Nov 19 nicklas 1627       return "PAD";
5740 20 Nov 19 nicklas 1628     }
5740 20 Nov 19 nicklas 1629
5740 20 Nov 19 nicklas 1630     @Override
5740 20 Nov 19 nicklas 1631     public BioSource convert(InputLine ctx) 
5740 20 Nov 19 nicklas 1632     {
5740 20 Nov 19 nicklas 1633       specimenQuery.setParameter("fromId", ctx.fromId, Type.STRING);
5740 20 Nov 19 nicklas 1634       currentSpecimen = specimenQuery.idList(dc);
5740 20 Nov 19 nicklas 1635       
5740 20 Nov 19 nicklas 1636       if (currentSpecimen.size() == 0) return null;
5740 20 Nov 19 nicklas 1637       
5740 20 Nov 19 nicklas 1638       patientQuery.setParameter("specimen", currentSpecimen, Type.INT);
5740 20 Nov 19 nicklas 1639       List<BioSource> patients = patientQuery.list(dc);
5740 20 Nov 19 nicklas 1640       if (patients.size() > 1)
5740 20 Nov 19 nicklas 1641       {
5740 20 Nov 19 nicklas 1642         throw new RuntimeException("On line " + ctx.lineNo + ": Found " + patients.size() + " patients with same PAD: " + ctx.fromId);
5740 20 Nov 19 nicklas 1643       }
5740 20 Nov 19 nicklas 1644       return patients.size() == 0 ? null : patients.get(0);
5740 20 Nov 19 nicklas 1645     }
5740 20 Nov 19 nicklas 1646     
5740 20 Nov 19 nicklas 1647     /**
5740 20 Nov 19 nicklas 1648       Create an output implementation for the specimen release id.
5740 20 Nov 19 nicklas 1649     */
5740 20 Nov 19 nicklas 1650     public OutputColumn toSpecimenId()
5740 20 Nov 19 nicklas 1651     {
5740 20 Nov 19 nicklas 1652       ItemQuery<Sample> query = Sample.getQuery();
5740 20 Nov 19 nicklas 1653       query.restrict(Restrictions.in(Hql.property("id"), Expressions.parameter("specimen")));
5740 20 Nov 19 nicklas 1654       return new PadToReleaseIdConverter("SpecimenId", dc, query, this);
5740 20 Nov 19 nicklas 1655     }
5740 20 Nov 19 nicklas 1656     
5740 20 Nov 19 nicklas 1657     /**
5740 20 Nov 19 nicklas 1658       Create an output implementation for the case release id.
5740 20 Nov 19 nicklas 1659     */
5740 20 Nov 19 nicklas 1660     public OutputColumn toCaseId()
5740 20 Nov 19 nicklas 1661     {
5740 20 Nov 19 nicklas 1662       ItemQuery<Sample> query = Sample.getQuery();
5740 20 Nov 19 nicklas 1663       Subtype.CASE.addFilter(dc, query);
5740 20 Nov 19 nicklas 1664       query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
5740 20 Nov 19 nicklas 1665       query.join(Hql.innerJoin("childCreationEvents", "cce"));
5740 20 Nov 19 nicklas 1666       query.join(Hql.innerJoin("cce", "event", "evt"));
5740 20 Nov 19 nicklas 1667       query.join(Hql.innerJoin("evt", "bioMaterial", "spm")); // 'spm' should now reference a specimen/nospecimen
5740 20 Nov 19 nicklas 1668       query.restrict(Restrictions.in(Hql.alias("spm"), Expressions.parameter("specimen")));
5740 20 Nov 19 nicklas 1669       return new PadToReleaseIdConverter("CaseId", dc, query, this);
5740 20 Nov 19 nicklas 1670     }
5740 20 Nov 19 nicklas 1671   }
5740 20 Nov 19 nicklas 1672   
5740 20 Nov 19 nicklas 1673   
5740 20 Nov 19 nicklas 1674   /**
5740 20 Nov 19 nicklas 1675     Implementation need to generate an output column
5740 20 Nov 19 nicklas 1676     for a given line.
5740 20 Nov 19 nicklas 1677   */
5740 20 Nov 19 nicklas 1678   static abstract class OutputColumn
5740 20 Nov 19 nicklas 1679     implements ValueConverter<InputLine, String>
5740 20 Nov 19 nicklas 1680   {
5740 20 Nov 19 nicklas 1681     
5740 20 Nov 19 nicklas 1682     private final String header;
5740 20 Nov 19 nicklas 1683     OutputColumn(String header)
5740 20 Nov 19 nicklas 1684     {
5740 20 Nov 19 nicklas 1685       this.header = header;
5740 20 Nov 19 nicklas 1686     }
5740 20 Nov 19 nicklas 1687     
5740 20 Nov 19 nicklas 1688     public String getHeader()
5740 20 Nov 19 nicklas 1689     {
5740 20 Nov 19 nicklas 1690       return header;
5740 20 Nov 19 nicklas 1691     }
5740 20 Nov 19 nicklas 1692   }
5740 20 Nov 19 nicklas 1693   
5740 20 Nov 19 nicklas 1694   /**
6474 04 Nov 21 nicklas 1695     Get the rest of the data on the line.
6474 04 Nov 21 nicklas 1696     @since 4.33.4
6474 04 Nov 21 nicklas 1697   */
6474 04 Nov 21 nicklas 1698   static class RestOfData
6474 04 Nov 21 nicklas 1699     extends OutputColumn
6474 04 Nov 21 nicklas 1700   {
6474 04 Nov 21 nicklas 1701     
6474 04 Nov 21 nicklas 1702     RestOfData(String restHeader)
6474 04 Nov 21 nicklas 1703     {
6474 04 Nov 21 nicklas 1704       super(restHeader);
6474 04 Nov 21 nicklas 1705     }
6474 04 Nov 21 nicklas 1706     
6474 04 Nov 21 nicklas 1707     @Override
6474 04 Nov 21 nicklas 1708     public String convert(InputLine ctx) 
6474 04 Nov 21 nicklas 1709     {
6474 04 Nov 21 nicklas 1710       return ctx.cols.length == 2 ? ctx.cols[1] : null;
6474 04 Nov 21 nicklas 1711     }
6474 04 Nov 21 nicklas 1712   }
6474 04 Nov 21 nicklas 1713   
6474 04 Nov 21 nicklas 1714   /**
5663 11 Oct 19 nicklas 1715     Get the external (release) ID from the patient.
5663 11 Oct 19 nicklas 1716   */
5663 11 Oct 19 nicklas 1717   static class PatientToReleaseIdConverter
5740 20 Nov 19 nicklas 1718     extends OutputColumn
5663 11 Oct 19 nicklas 1719   {
5663 11 Oct 19 nicklas 1720     PatientToReleaseIdConverter()
5740 20 Nov 19 nicklas 1721     {
5740 20 Nov 19 nicklas 1722       super("PatientId");
5740 20 Nov 19 nicklas 1723     }
5663 11 Oct 19 nicklas 1724
5663 11 Oct 19 nicklas 1725     @Override
5740 20 Nov 19 nicklas 1726     public String convert(InputLine ctx) 
5663 11 Oct 19 nicklas 1727     {
5740 20 Nov 19 nicklas 1728       return ctx.patient.getExternalId();
5663 11 Oct 19 nicklas 1729     }
5663 11 Oct 19 nicklas 1730   }
5663 11 Oct 19 nicklas 1731   
5663 11 Oct 19 nicklas 1732   /**
5663 11 Oct 19 nicklas 1733     Get the external (release) ID for all cases
5663 11 Oct 19 nicklas 1734     related to the patient.
5663 11 Oct 19 nicklas 1735   */
5663 11 Oct 19 nicklas 1736   static class PatientToCaseReleaseIdConverter
5740 20 Nov 19 nicklas 1737     extends OutputColumn
5663 11 Oct 19 nicklas 1738   {
5663 11 Oct 19 nicklas 1739     private final DbControl dc;
5663 11 Oct 19 nicklas 1740     private final ItemQuery<Sample> caseQuery;
5663 11 Oct 19 nicklas 1741     private final Formatter<BioMaterial> toRelaseId;
5663 11 Oct 19 nicklas 1742     
5663 11 Oct 19 nicklas 1743     PatientToCaseReleaseIdConverter(DbControl dc)
5663 11 Oct 19 nicklas 1744     {
5740 20 Nov 19 nicklas 1745       super("CaseId");
5663 11 Oct 19 nicklas 1746       this.dc = dc;
5663 11 Oct 19 nicklas 1747       this.toRelaseId = new ToReleaseIdFormatter();
5663 11 Oct 19 nicklas 1748       caseQuery = Sample.getQuery();
5663 11 Oct 19 nicklas 1749       Subtype.CASE.addFilter(dc, caseQuery);
5663 11 Oct 19 nicklas 1750       caseQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
5663 11 Oct 19 nicklas 1751       caseQuery.join(Hql.innerJoin("parent", "pat"));
5663 11 Oct 19 nicklas 1752       caseQuery.restrict(Restrictions.eq(Hql.alias("pat"), Hql.entityParameter("pat", Item.BIOSOURCE)));
5663 11 Oct 19 nicklas 1753       caseQuery.order(Orders.asc(Hql.property("externalId")));
5663 11 Oct 19 nicklas 1754     }
5663 11 Oct 19 nicklas 1755   
5663 11 Oct 19 nicklas 1756     @Override
5740 20 Nov 19 nicklas 1757     public String convert(InputLine ctx) 
5663 11 Oct 19 nicklas 1758     {
5740 20 Nov 19 nicklas 1759       caseQuery.setEntityParameter("pat", ctx.patient);
5663 11 Oct 19 nicklas 1760       List<Sample> cases = caseQuery.list(dc);
5663 11 Oct 19 nicklas 1761       return Values.getString(cases, ",", true, toRelaseId);
5663 11 Oct 19 nicklas 1762     }
5663 11 Oct 19 nicklas 1763   }
5663 11 Oct 19 nicklas 1764   
5663 11 Oct 19 nicklas 1765   /**
6510 03 Dec 21 nicklas 1766     Get the external (release) ID for all specimen or no-specimen
5663 11 Oct 19 nicklas 1767     related to the patient.
5663 11 Oct 19 nicklas 1768   */
5663 11 Oct 19 nicklas 1769   static class PatientToSpecimenReleaseIdConverter
5740 20 Nov 19 nicklas 1770     extends OutputColumn
5663 11 Oct 19 nicklas 1771   {
5663 11 Oct 19 nicklas 1772     private final DbControl dc;
5663 11 Oct 19 nicklas 1773     private final ItemQuery<Sample> specimenQuery;
5663 11 Oct 19 nicklas 1774     private final Formatter<BioMaterial> toRelaseId;
5663 11 Oct 19 nicklas 1775     
5663 11 Oct 19 nicklas 1776     PatientToSpecimenReleaseIdConverter(DbControl dc)
5663 11 Oct 19 nicklas 1777     {
5740 20 Nov 19 nicklas 1778       super("SpecimenId");
5663 11 Oct 19 nicklas 1779       this.dc = dc;
5663 11 Oct 19 nicklas 1780       this.toRelaseId = new ToReleaseIdFormatter();
5663 11 Oct 19 nicklas 1781       specimenQuery = Sample.getQuery();
5663 11 Oct 19 nicklas 1782       specimenQuery.restrict(
5663 11 Oct 19 nicklas 1783         Restrictions.or(
5663 11 Oct 19 nicklas 1784           Subtype.SPECIMEN.restriction(dc, null),
6510 03 Dec 21 nicklas 1785           Subtype.NO_SPECIMEN.restriction(dc, null)
5663 11 Oct 19 nicklas 1786         ));
5663 11 Oct 19 nicklas 1787       specimenQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
5663 11 Oct 19 nicklas 1788       specimenQuery.join(Hql.innerJoin("parent", "cse"));
5663 11 Oct 19 nicklas 1789       specimenQuery.join(Hql.innerJoin("cse", "parent", "pat"));
5663 11 Oct 19 nicklas 1790       specimenQuery.restrict(Restrictions.eq(Hql.alias("pat"), Hql.entityParameter("pat", Item.BIOSOURCE)));
5663 11 Oct 19 nicklas 1791       specimenQuery.order(Orders.asc(Hql.property("externalId")));
5663 11 Oct 19 nicklas 1792     }
5663 11 Oct 19 nicklas 1793   
5663 11 Oct 19 nicklas 1794     @Override
5740 20 Nov 19 nicklas 1795     public String convert(InputLine ctx) 
5663 11 Oct 19 nicklas 1796     {
5740 20 Nov 19 nicklas 1797       specimenQuery.setEntityParameter("pat", ctx.patient);
5663 11 Oct 19 nicklas 1798       List<Sample> specimen = specimenQuery.list(dc);
5663 11 Oct 19 nicklas 1799       return Values.getString(specimen, ",", true, toRelaseId);
5663 11 Oct 19 nicklas 1800     }
5663 11 Oct 19 nicklas 1801   }
5663 11 Oct 19 nicklas 1802
5663 11 Oct 19 nicklas 1803   /**
5663 11 Oct 19 nicklas 1804     Get the personal number for the patient.
5663 11 Oct 19 nicklas 1805   */
5663 11 Oct 19 nicklas 1806   static class PatientToPersonalNumberConverter
5740 20 Nov 19 nicklas 1807     extends OutputColumn
5663 11 Oct 19 nicklas 1808   {
5663 11 Oct 19 nicklas 1809     
5663 11 Oct 19 nicklas 1810     private final DbControl dc;
5663 11 Oct 19 nicklas 1811     private final SnapshotManager manager;
5663 11 Oct 19 nicklas 1812     
5663 11 Oct 19 nicklas 1813     PatientToPersonalNumberConverter(DbControl dc, SnapshotManager manager)
5663 11 Oct 19 nicklas 1814     {
5740 20 Nov 19 nicklas 1815       super("PersonalNumber");
5663 11 Oct 19 nicklas 1816       this.dc = dc;
5663 11 Oct 19 nicklas 1817       this.manager = manager;
5663 11 Oct 19 nicklas 1818     }
5663 11 Oct 19 nicklas 1819   
5663 11 Oct 19 nicklas 1820     @Override
5740 20 Nov 19 nicklas 1821     public String convert(InputLine ctx) 
5663 11 Oct 19 nicklas 1822     {
5740 20 Nov 19 nicklas 1823       return (String)Annotationtype.PERSONAL_NUMBER.getAnnotationValue(dc, manager, ctx.patient);
5663 11 Oct 19 nicklas 1824     }
5663 11 Oct 19 nicklas 1825   }
5663 11 Oct 19 nicklas 1826   
5740 20 Nov 19 nicklas 1827   /**
5740 20 Nov 19 nicklas 1828     Maps a release id from patient, case or specimen to PAD
5740 20 Nov 19 nicklas 1829     (one or more) on specimen items. Use one of the factor methods
5740 20 Nov 19 nicklas 1830     to get an instance for the proper release id type.
5740 20 Nov 19 nicklas 1831   */
5740 20 Nov 19 nicklas 1832   static class ReleaseIdToPadConverter
5740 20 Nov 19 nicklas 1833     extends OutputColumn
5740 20 Nov 19 nicklas 1834   {
5740 20 Nov 19 nicklas 1835     private final DbControl dc;
5740 20 Nov 19 nicklas 1836     private final SnapshotManager manager;
5740 20 Nov 19 nicklas 1837     private final ItemQuery<Sample> specimenQuery;
5740 20 Nov 19 nicklas 1838     
5740 20 Nov 19 nicklas 1839     /**
5740 20 Nov 19 nicklas 1840       Get the PAD when the source id is a specimen release id.
5740 20 Nov 19 nicklas 1841     */
5740 20 Nov 19 nicklas 1842     static ReleaseIdToPadConverter fromSpecimenId(DbControl dc, SnapshotManager manager)
5740 20 Nov 19 nicklas 1843     {
5740 20 Nov 19 nicklas 1844       ItemQuery<Sample> query = Sample.getQuery();
5740 20 Nov 19 nicklas 1845       query.restrict(Restrictions.eq(Hql.property("externalId"), Expressions.parameter("fromId")));
5740 20 Nov 19 nicklas 1846       return new ReleaseIdToPadConverter(dc, manager, query);
5740 20 Nov 19 nicklas 1847     }
5740 20 Nov 19 nicklas 1848     
5740 20 Nov 19 nicklas 1849     /**
5740 20 Nov 19 nicklas 1850       Get the PAD(s) when the source id is a case release id.
5740 20 Nov 19 nicklas 1851     */
5740 20 Nov 19 nicklas 1852     static ReleaseIdToPadConverter fromCaseId(DbControl dc, SnapshotManager manager)
5740 20 Nov 19 nicklas 1853     {
5740 20 Nov 19 nicklas 1854       ItemQuery<Sample> query = Sample.getQuery();
5740 20 Nov 19 nicklas 1855       query.join(Hql.innerJoin("parent", "cse"));
5740 20 Nov 19 nicklas 1856       query.restrict(Restrictions.eq(Hql.property("cse", "externalId"), Expressions.parameter("fromId")));
5740 20 Nov 19 nicklas 1857       return new ReleaseIdToPadConverter(dc, manager, query);
5740 20 Nov 19 nicklas 1858     }
5740 20 Nov 19 nicklas 1859     
5740 20 Nov 19 nicklas 1860     /**
5740 20 Nov 19 nicklas 1861       Get the PAD(s) when the source id is a patient release id.
5740 20 Nov 19 nicklas 1862     */
5740 20 Nov 19 nicklas 1863     static ReleaseIdToPadConverter fromPatientId(DbControl dc, SnapshotManager manager)
5740 20 Nov 19 nicklas 1864     {
5740 20 Nov 19 nicklas 1865       ItemQuery<Sample> query = Sample.getQuery();
5740 20 Nov 19 nicklas 1866       query.join(Hql.innerJoin("parent", "cse"));
5740 20 Nov 19 nicklas 1867       query.join(Hql.innerJoin("cse", "parent", "pat"));
5740 20 Nov 19 nicklas 1868       query.restrict(Restrictions.eq(Hql.property("pat", "externalId"), Expressions.parameter("fromId")));
5740 20 Nov 19 nicklas 1869       return new ReleaseIdToPadConverter(dc, manager, query);
5740 20 Nov 19 nicklas 1870     }
5740 20 Nov 19 nicklas 1871     
5740 20 Nov 19 nicklas 1872     private ReleaseIdToPadConverter(DbControl dc, SnapshotManager manager, ItemQuery<Sample> specimenQuery)
5740 20 Nov 19 nicklas 1873     {
5740 20 Nov 19 nicklas 1874       super("PAD");
5740 20 Nov 19 nicklas 1875       this.dc = dc;
5740 20 Nov 19 nicklas 1876       this.manager = manager;
5740 20 Nov 19 nicklas 1877       this.specimenQuery = specimenQuery;
5740 20 Nov 19 nicklas 1878       specimenQuery.restrict(
5740 20 Nov 19 nicklas 1879         Restrictions.or(
5740 20 Nov 19 nicklas 1880           Subtype.SPECIMEN.restriction(dc, null),
6510 03 Dec 21 nicklas 1881           Subtype.NO_SPECIMEN.restriction(dc, null)
5740 20 Nov 19 nicklas 1882         ));
5740 20 Nov 19 nicklas 1883       specimenQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
5740 20 Nov 19 nicklas 1884     }
5740 20 Nov 19 nicklas 1885   
5740 20 Nov 19 nicklas 1886     @Override
5740 20 Nov 19 nicklas 1887     public String convert(InputLine ctx) 
5740 20 Nov 19 nicklas 1888     {
5740 20 Nov 19 nicklas 1889       specimenQuery.setParameter("fromId", ctx.fromId, Type.STRING);
5740 20 Nov 19 nicklas 1890       List<Sample> specimen = specimenQuery.list(dc);
5740 20 Nov 19 nicklas 1891       String pad = null;
5740 20 Nov 19 nicklas 1892       if (specimen.size() > 1)
5740 20 Nov 19 nicklas 1893       {
5740 20 Nov 19 nicklas 1894         Set<String> allPad = new TreeSet<>();
5740 20 Nov 19 nicklas 1895         for (Sample s : specimen)
5740 20 Nov 19 nicklas 1896         {
5861 11 Mar 20 nicklas 1897           String p = (String)Annotationtype.PAD.getAnnotationValue(dc, manager, s);
5861 11 Mar 20 nicklas 1898           if (p != null) allPad.add(p);
5740 20 Nov 19 nicklas 1899         }
5740 20 Nov 19 nicklas 1900         pad = Values.getString(allPad, ",", true);
5740 20 Nov 19 nicklas 1901       }
5740 20 Nov 19 nicklas 1902       else if (specimen.size() == 1)
5740 20 Nov 19 nicklas 1903       {
5740 20 Nov 19 nicklas 1904         pad = (String)Annotationtype.PAD.getAnnotationValue(dc, manager, specimen.get(0));
5740 20 Nov 19 nicklas 1905       }
5740 20 Nov 19 nicklas 1906       return pad;
5740 20 Nov 19 nicklas 1907     }
5740 20 Nov 19 nicklas 1908     
5740 20 Nov 19 nicklas 1909   }
5740 20 Nov 19 nicklas 1910   
5740 20 Nov 19 nicklas 1911   /**
5740 20 Nov 19 nicklas 1912     Output release id for case or specimen items that has been previously found by the
5740 20 Nov 19 nicklas 1913     PatientLoaderFromPad implementation.
5740 20 Nov 19 nicklas 1914   */
5740 20 Nov 19 nicklas 1915   static class PadToReleaseIdConverter
5740 20 Nov 19 nicklas 1916     extends OutputColumn
5740 20 Nov 19 nicklas 1917   {
5740 20 Nov 19 nicklas 1918     
5740 20 Nov 19 nicklas 1919     
5740 20 Nov 19 nicklas 1920     private final DbControl dc;
5740 20 Nov 19 nicklas 1921     private final ItemQuery<Sample> query;
5740 20 Nov 19 nicklas 1922     private final PatientLoaderFromPad padLoader;
5740 20 Nov 19 nicklas 1923     
5740 20 Nov 19 nicklas 1924     private PadToReleaseIdConverter(String header, DbControl dc, ItemQuery<Sample> query, PatientLoaderFromPad padLoader)
5740 20 Nov 19 nicklas 1925     {
5740 20 Nov 19 nicklas 1926       super(header);
5740 20 Nov 19 nicklas 1927       this.dc = dc;
5740 20 Nov 19 nicklas 1928       this.query = query;
5740 20 Nov 19 nicklas 1929       this.padLoader = padLoader;
5740 20 Nov 19 nicklas 1930     }
5740 20 Nov 19 nicklas 1931     
5740 20 Nov 19 nicklas 1932     @Override
5740 20 Nov 19 nicklas 1933     public String convert(InputLine ctx) 
5740 20 Nov 19 nicklas 1934     {
5740 20 Nov 19 nicklas 1935       if (padLoader.currentSpecimen.size() == 0) return null;
5740 20 Nov 19 nicklas 1936       
5740 20 Nov 19 nicklas 1937       query.setParameter("specimen", padLoader.currentSpecimen, Type.INT);
5740 20 Nov 19 nicklas 1938       List<Sample> items = query.list(dc);
5740 20 Nov 19 nicklas 1939       String idValues = null;
5740 20 Nov 19 nicklas 1940       if (items.size() > 1)
5740 20 Nov 19 nicklas 1941       {
5740 20 Nov 19 nicklas 1942         Set<String> allId = new TreeSet<>();
5740 20 Nov 19 nicklas 1943         for (Sample s : items)
5740 20 Nov 19 nicklas 1944         {
5861 11 Mar 20 nicklas 1945           String id = s.getExternalId();
5861 11 Mar 20 nicklas 1946           if (id != null) allId.add(id);
5740 20 Nov 19 nicklas 1947         }
5740 20 Nov 19 nicklas 1948         idValues = Values.getString(allId, ",", true);
5740 20 Nov 19 nicklas 1949       }
5740 20 Nov 19 nicklas 1950       else if (items.size() == 1)
5740 20 Nov 19 nicklas 1951       {
5740 20 Nov 19 nicklas 1952         idValues = items.get(0).getExternalId();
5740 20 Nov 19 nicklas 1953       }
5740 20 Nov 19 nicklas 1954       return idValues;
5740 20 Nov 19 nicklas 1955     }
5740 20 Nov 19 nicklas 1956
5740 20 Nov 19 nicklas 1957   }
5740 20 Nov 19 nicklas 1958   
5663 11 Oct 19 nicklas 1959   static class ToReleaseIdFormatter
5663 11 Oct 19 nicklas 1960     implements Formatter<BioMaterial>
5663 11 Oct 19 nicklas 1961   {
5663 11 Oct 19 nicklas 1962
5663 11 Oct 19 nicklas 1963     @Override
5663 11 Oct 19 nicklas 1964     public String format(BioMaterial item) 
5663 11 Oct 19 nicklas 1965     {
5663 11 Oct 19 nicklas 1966       return item.getExternalId();
5663 11 Oct 19 nicklas 1967     }
5663 11 Oct 19 nicklas 1968     @Override
5663 11 Oct 19 nicklas 1969     public BioMaterial parseString(String s) 
5663 11 Oct 19 nicklas 1970     {
5663 11 Oct 19 nicklas 1971       return null;
5663 11 Oct 19 nicklas 1972     }
5663 11 Oct 19 nicklas 1973   }
5663 11 Oct 19 nicklas 1974   
5663 11 Oct 19 nicklas 1975   static class OrderByFirstColumn
5663 11 Oct 19 nicklas 1976     implements Comparator<Object[]>
5663 11 Oct 19 nicklas 1977   {
5663 11 Oct 19 nicklas 1978
5663 11 Oct 19 nicklas 1979     @Override
5663 11 Oct 19 nicklas 1980     public int compare(Object[] o1, Object[] o2) 
5663 11 Oct 19 nicklas 1981     {
5663 11 Oct 19 nicklas 1982       String s1 = (String)o1[0];
5663 11 Oct 19 nicklas 1983       String s2 = (String)o2[0];
5663 11 Oct 19 nicklas 1984       return s1.compareTo(s2);
5663 11 Oct 19 nicklas 1985     }
5663 11 Oct 19 nicklas 1986   }
5663 11 Oct 19 nicklas 1987   
1634 02 May 12 nicklas 1988 }