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

Code
Comments
Other
Rev Date Author Line
6200 08 Apr 21 nicklas 1 package net.sf.basedb.reggie.plugins.cmd;
6200 08 Apr 21 nicklas 2
6200 08 Apr 21 nicklas 3 import java.util.ArrayList;
6346 16 Aug 21 nicklas 4 import java.util.Arrays;
6353 18 Aug 21 nicklas 5 import java.util.Date;
6671 07 Apr 22 nicklas 6 import java.util.HashSet;
6200 08 Apr 21 nicklas 7 import java.util.List;
6974 13 Jan 23 nicklas 8 import java.util.Map;
6701 26 Apr 22 nicklas 9 import java.util.Map.Entry;
6671 07 Apr 22 nicklas 10 import java.util.Set;
6200 08 Apr 21 nicklas 11
6200 08 Apr 21 nicklas 12 import org.json.simple.JSONArray;
6200 08 Apr 21 nicklas 13 import org.json.simple.JSONObject;
6974 13 Jan 23 nicklas 14 import org.json.simple.parser.ContainerFactory;
6200 08 Apr 21 nicklas 15 import org.json.simple.parser.JSONParser;
6200 08 Apr 21 nicklas 16
6200 08 Apr 21 nicklas 17 import net.sf.basedb.core.DbControl;
6200 08 Apr 21 nicklas 18 import net.sf.basedb.core.FileServer;
6898 29 Nov 22 nicklas 19 import net.sf.basedb.core.ProgressReporter;
6200 08 Apr 21 nicklas 20 import net.sf.basedb.opengrid.CmdResult;
6200 08 Apr 21 nicklas 21 import net.sf.basedb.opengrid.OpenGrid;
6200 08 Apr 21 nicklas 22 import net.sf.basedb.opengrid.RemoteHost;
6200 08 Apr 21 nicklas 23 import net.sf.basedb.opengrid.RemoteSession;
6200 08 Apr 21 nicklas 24 import net.sf.basedb.opengrid.config.ConnectionInfo;
6200 08 Apr 21 nicklas 25 import net.sf.basedb.opengrid.filetransfer.ByteArrayDownloadTarget;
6353 18 Aug 21 nicklas 26 import net.sf.basedb.opengrid.filetransfer.FileMetaData;
6209 13 Apr 21 nicklas 27 import net.sf.basedb.opengrid.filetransfer.FilePermission;
6209 13 Apr 21 nicklas 28 import net.sf.basedb.opengrid.filetransfer.StringUploadSource;
6209 13 Apr 21 nicklas 29 import net.sf.basedb.opengrid.filetransfer.UploadSource;
6353 18 Aug 21 nicklas 30 import net.sf.basedb.reggie.Reggie;
6200 08 Apr 21 nicklas 31 import net.sf.basedb.reggie.grid.ScriptUtil;
6341 29 Jun 21 nicklas 32 import net.sf.basedb.reggie.plugins.cmd.ScanBIdRef.SampleIdType;
6200 08 Apr 21 nicklas 33 import net.sf.basedb.util.error.ThrowableUtil;
6200 08 Apr 21 nicklas 34
6200 08 Apr 21 nicklas 35 /**
6200 08 Apr 21 nicklas 36   Represents a JSON file with incoming data that should be imported.
6200 08 Apr 21 nicklas 37   
6200 08 Apr 21 nicklas 38   @since 4.32
6200 08 Apr 21 nicklas 39  */
6200 08 Apr 21 nicklas 40 public class JsonFile
6200 08 Apr 21 nicklas 41 {
6200 08 Apr 21 nicklas 42   /**
6200 08 Apr 21 nicklas 43     Search the file server for *.json files.
6200 08 Apr 21 nicklas 44   */
6929 02 Dec 22 nicklas 45   public static List<JsonFile> findJsonFiles(DbControl dc, FileServer server, ImportContext ctx, boolean downloadAndParse, int maxFullValidation, ProgressReporter progress)
6200 08 Apr 21 nicklas 46   {
6200 08 Apr 21 nicklas 47     List<JsonFile> importFiles = new ArrayList<>();
6200 08 Apr 21 nicklas 48
6200 08 Apr 21 nicklas 49     // Get the import archive and connect to it via SSH
6200 08 Apr 21 nicklas 50     RemoteHost host = new RemoteHost(new ConnectionInfo(server));
6200 08 Apr 21 nicklas 51     String rootPath = ScriptUtil.checkValidPath(server.getRootPath(), true, false);
6200 08 Apr 21 nicklas 52     RemoteSession session = null;
6200 08 Apr 21 nicklas 53     try
6200 08 Apr 21 nicklas 54     {
6200 08 Apr 21 nicklas 55
6200 08 Apr 21 nicklas 56       session = host.connect(5);
6200 08 Apr 21 nicklas 57       // The 'find' command will find all *.json files. Output:
6200 08 Apr 21 nicklas 58       // 0: filename without path
6897 29 Nov 22 nicklas 59       String findCmd = "find " + rootPath + " -maxdepth 1 -type f -name '*.json' -printf '%TY%Tm%Td %f\\n' | sort -n";
6200 08 Apr 21 nicklas 60       CmdResult<String> find = session.executeCmd(findCmd, 60);
6341 29 Jun 21 nicklas 61       find.throwExceptionIfNonZeroExitStatus();    
6200 08 Apr 21 nicklas 62       String[] lines = find.getStdout().split("\\n");
6346 16 Aug 21 nicklas 63       Arrays.sort(lines);
6929 02 Dec 22 nicklas 64       if (ctx == null) ctx = new ImportContext();
6894 25 Nov 22 nicklas 65
6898 29 Nov 22 nicklas 66       // To get all info for fastq files
6894 25 Nov 22 nicklas 67       // find . -maxdepth 1 -type f -name '*.fastq.gz' -printf "%P;%s;%TY%Tm%Td %TH%TM\n"
6894 25 Nov 22 nicklas 68       if (downloadAndParse)
6894 25 Nov 22 nicklas 69       {
6894 25 Nov 22 nicklas 70         // Also pre-load information about existing FASTQ files
6894 25 Nov 22 nicklas 71         String findFastqCmd = "find " + rootPath + " -maxdepth 1 -type f -name '*.fastq.gz' -printf '%P;%s;%TY%Tm%Td %TH%TM\\n'";
6894 25 Nov 22 nicklas 72         CmdResult<String> findFastq = session.executeCmd(findFastqCmd, 60);
6894 25 Nov 22 nicklas 73         findFastq.throwExceptionIfNonZeroExitStatus();    
6894 25 Nov 22 nicklas 74         String[] fastqLines = findFastq.getStdout().split("\\n");
6894 25 Nov 22 nicklas 75         for (String line : fastqLines)
6894 25 Nov 22 nicklas 76         {
6894 25 Nov 22 nicklas 77           if (line == null || line.length() == 0) continue;
6894 25 Nov 22 nicklas 78           String[] info = line.split(";");
6894 25 Nov 22 nicklas 79           FileMetaData fastq = new FileMetaData();
6894 25 Nov 22 nicklas 80           fastq.setSize(Long.parseLong(info[1]));
6894 25 Nov 22 nicklas 81           fastq.setLastModifiedTime(Reggie.CONVERTER_STRING_TO_DATETIME.convert(info[2]).getTime());
6894 25 Nov 22 nicklas 82           ctx.setFileInfo(info[0], fastq);
6894 25 Nov 22 nicklas 83         }
6894 25 Nov 22 nicklas 84       }
6894 25 Nov 22 nicklas 85       
6895 25 Nov 22 nicklas 86       int numParsed = 0;
6897 29 Nov 22 nicklas 87       int numValidated = 0;
6898 29 Nov 22 nicklas 88       int numFiles = lines.length;
6897 29 Nov 22 nicklas 89       Set<String> flowCellIdToForceValidate = new HashSet<>();
6898 29 Nov 22 nicklas 90       for (int lineNo = 0; lineNo < lines.length; lineNo++)
6200 08 Apr 21 nicklas 91       {
6898 29 Nov 22 nicklas 92         String line = lines[lineNo];
6341 29 Jun 21 nicklas 93         if (line == null || line.length() == 0) continue;
6897 29 Nov 22 nicklas 94         JsonFile file = new JsonFile(dc, line.split("\\s")[1]);
6898 29 Nov 22 nicklas 95         
6200 08 Apr 21 nicklas 96         if (downloadAndParse)
6200 08 Apr 21 nicklas 97         {
6898 29 Nov 22 nicklas 98           if (progress != null)
6898 29 Nov 22 nicklas 99           {
6898 29 Nov 22 nicklas 100             progress.display(2+(95*lineNo)/numFiles, "Parsing '"+file.name+"'... ("+lineNo+" of "+numFiles+
6898 29 Nov 22 nicklas 101                 " files on " + server.getName()+":"+server.getRootPath()+")");
6898 29 Nov 22 nicklas 102           }
6895 25 Nov 22 nicklas 103           boolean fullValidation = maxFullValidation < 0 || numParsed < maxFullValidation;
6897 29 Nov 22 nicklas 104           file.downloadAndParse(session, rootPath, fullValidation, flowCellIdToForceValidate, ctx);
6897 29 Nov 22 nicklas 105           if (file.fullyValidated) numValidated++;
6897 29 Nov 22 nicklas 106           // We keep track of all flow cells that was valdiated before reaching max number
6897 29 Nov 22 nicklas 107           // so that we can also force validate additional JSON files with the same flow cell
6897 29 Nov 22 nicklas 108           if (fullValidation && file.flowCellInfo != null) 
6897 29 Nov 22 nicklas 109           {
6897 29 Nov 22 nicklas 110             flowCellIdToForceValidate.add(file.flowCellInfo.flowCellId);
6897 29 Nov 22 nicklas 111           }
6895 25 Nov 22 nicklas 112           numParsed++;
6200 08 Apr 21 nicklas 113         }
6200 08 Apr 21 nicklas 114         importFiles.add(file);
6897 29 Nov 22 nicklas 115         //For debug
6899 29 Nov 22 nicklas 116         //if (importFiles.size() > 60) break;
6200 08 Apr 21 nicklas 117       }
6200 08 Apr 21 nicklas 118     }
6200 08 Apr 21 nicklas 119     finally
6200 08 Apr 21 nicklas 120     {
6200 08 Apr 21 nicklas 121       OpenGrid.close(session);
6200 08 Apr 21 nicklas 122     }
6200 08 Apr 21 nicklas 123     
6200 08 Apr 21 nicklas 124     return importFiles;
6200 08 Apr 21 nicklas 125   }
6200 08 Apr 21 nicklas 126
6671 07 Apr 22 nicklas 127   /**
6896 28 Nov 22 nicklas 128     Get a information about a single JSON file on the server that is already known.
6896 28 Nov 22 nicklas 129     @since 4.41
6896 28 Nov 22 nicklas 130   */
6896 28 Nov 22 nicklas 131   public static JsonFile getJsonFile(DbControl dc, FileServer server, String filename, boolean downloadAndParse)
6896 28 Nov 22 nicklas 132   {
6896 28 Nov 22 nicklas 133     // Get the import archive and connect to it via SSH
6896 28 Nov 22 nicklas 134     RemoteSession session = null;
7256 13 Jun 23 nicklas 135     JsonFile file = new JsonFile(dc, filename);
7256 13 Jun 23 nicklas 136     if (downloadAndParse)
6896 28 Nov 22 nicklas 137     {
7256 13 Jun 23 nicklas 138       RemoteHost host = new RemoteHost(new ConnectionInfo(server));
7256 13 Jun 23 nicklas 139       String rootPath = ScriptUtil.checkValidPath(server.getRootPath(), true, false);
7256 13 Jun 23 nicklas 140       try
6896 28 Nov 22 nicklas 141       {
7256 13 Jun 23 nicklas 142         session = host.connect(5);
7256 13 Jun 23 nicklas 143         ImportContext ctx = new ImportContext();
6897 29 Nov 22 nicklas 144         file.downloadAndParse(session, rootPath, true, null, ctx);
6896 28 Nov 22 nicklas 145       }
7256 13 Jun 23 nicklas 146       finally
7256 13 Jun 23 nicklas 147       {
7256 13 Jun 23 nicklas 148         OpenGrid.close(session);
7256 13 Jun 23 nicklas 149       }
6896 28 Nov 22 nicklas 150     }
6896 28 Nov 22 nicklas 151     return file;
6896 28 Nov 22 nicklas 152   }
6896 28 Nov 22 nicklas 153   
6896 28 Nov 22 nicklas 154   /**
6671 07 Apr 22 nicklas 155     Search the file server for *.fastq.gz files pairs. The R1 and R2 in filenames
6671 07 Apr 22 nicklas 156     are replaced with R#. There is no check that both R1 and R2 exists.
6671 07 Apr 22 nicklas 157     @since 4.38
6671 07 Apr 22 nicklas 158   */
6671 07 Apr 22 nicklas 159   public static Set<String> findFastqPairs(DbControl dc, FileServer server)
6671 07 Apr 22 nicklas 160   {
6671 07 Apr 22 nicklas 161     Set<String> fastqFiles = new HashSet<>();
6200 08 Apr 21 nicklas 162   
6671 07 Apr 22 nicklas 163     // Get the import archive and connect to it via SSH
6671 07 Apr 22 nicklas 164     RemoteHost host = new RemoteHost(new ConnectionInfo(server));
6671 07 Apr 22 nicklas 165     String rootPath = ScriptUtil.checkValidPath(server.getRootPath(), true, false);
6671 07 Apr 22 nicklas 166     RemoteSession session = null;
6671 07 Apr 22 nicklas 167     try
6671 07 Apr 22 nicklas 168     {
6671 07 Apr 22 nicklas 169   
6671 07 Apr 22 nicklas 170       session = host.connect(5);
6671 07 Apr 22 nicklas 171       // The 'find' command will find all *.fastq.gz files. Output:
6671 07 Apr 22 nicklas 172       // 0: filename without path
6671 07 Apr 22 nicklas 173       
6671 07 Apr 22 nicklas 174       String findCmd = "find " + rootPath + " -maxdepth 1 -type f -name *.fastq.gz -printf '%f\\n'";
6671 07 Apr 22 nicklas 175       CmdResult<String> find = session.executeCmd(findCmd, 60);
6671 07 Apr 22 nicklas 176       find.throwExceptionIfNonZeroExitStatus();
6671 07 Apr 22 nicklas 177       String allNames = find.getStdout().replaceAll("R\\d", "R#");
6671 07 Apr 22 nicklas 178       String[] lines = allNames.split("\\n");
6671 07 Apr 22 nicklas 179       Arrays.sort(lines);
6671 07 Apr 22 nicklas 180       for (String line : lines)
6671 07 Apr 22 nicklas 181       {
6671 07 Apr 22 nicklas 182         if (line == null || line.length() == 0) continue;
6671 07 Apr 22 nicklas 183         fastqFiles.add(line);
6671 07 Apr 22 nicklas 184       }
6671 07 Apr 22 nicklas 185     }
6671 07 Apr 22 nicklas 186     finally
6671 07 Apr 22 nicklas 187     {
6671 07 Apr 22 nicklas 188       OpenGrid.close(session);
6671 07 Apr 22 nicklas 189     }
6671 07 Apr 22 nicklas 190     
6671 07 Apr 22 nicklas 191     return fastqFiles;
6671 07 Apr 22 nicklas 192   }
6671 07 Apr 22 nicklas 193
6201 09 Apr 21 nicklas 194   private final DbControl dc;
6200 08 Apr 21 nicklas 195   private final String name;
6200 08 Apr 21 nicklas 196   private final List<String> errorMessages;
6200 08 Apr 21 nicklas 197   private final List<String> warningMessages;
6200 08 Apr 21 nicklas 198   private final List<String> debugMessages;
6200 08 Apr 21 nicklas 199
6212 14 Apr 21 nicklas 200   private String operator;
6212 14 Apr 21 nicklas 201   
6209 13 Apr 21 nicklas 202   private String rawData;
6200 08 Apr 21 nicklas 203   private JSONObject json;
6353 18 Aug 21 nicklas 204   private long size;
6353 18 Aug 21 nicklas 205   private long lastModified;
6895 25 Nov 22 nicklas 206   private boolean fullyValidated;
6897 29 Nov 22 nicklas 207   private String flowCellId;
6911 30 Nov 22 nicklas 208   private String sequencingStartDate;
6200 08 Apr 21 nicklas 209
6341 29 Jun 21 nicklas 210   private MainInfo mainInfo;
6200 08 Apr 21 nicklas 211   private FastqInfo fastqInfo;
6217 19 Apr 21 nicklas 212   private SpecimenInfo specimenInfo;
6207 12 Apr 21 nicklas 213   private LysateInfo lysateInfo;
6207 12 Apr 21 nicklas 214   private RnaInfo rnaInfo;
6207 12 Apr 21 nicklas 215   private DnaInfo dnaInfo;
6207 12 Apr 21 nicklas 216   private FlowThroughInfo flowThroughInfo;
6200 08 Apr 21 nicklas 217   private LibraryInfo libInfo;
6200 08 Apr 21 nicklas 218   private PoolInfo poolInfo;
6201 09 Apr 21 nicklas 219   private FlowCellInfo flowCellInfo;
6201 09 Apr 21 nicklas 220   private SequencingRunInfo seqRunInfo;
6203 09 Apr 21 nicklas 221   private DemuxInfo demuxInfo;
6200 08 Apr 21 nicklas 222
6200 08 Apr 21 nicklas 223   /**
6200 08 Apr 21 nicklas 224     Creates a new file with the given name.
6200 08 Apr 21 nicklas 225   */
6201 09 Apr 21 nicklas 226   public JsonFile(DbControl dc, String name)
6200 08 Apr 21 nicklas 227   {
6201 09 Apr 21 nicklas 228     this.dc = dc;
6200 08 Apr 21 nicklas 229     this.name = name;
6200 08 Apr 21 nicklas 230     this.errorMessages = new ArrayList<String>();
6200 08 Apr 21 nicklas 231     this.warningMessages = new ArrayList<String>();
6200 08 Apr 21 nicklas 232     this.debugMessages = new ArrayList<String>();
6200 08 Apr 21 nicklas 233   }
6200 08 Apr 21 nicklas 234   
6201 09 Apr 21 nicklas 235   public DbControl dc()
6201 09 Apr 21 nicklas 236   {
6201 09 Apr 21 nicklas 237     return dc;
6201 09 Apr 21 nicklas 238   }
6201 09 Apr 21 nicklas 239   
6200 08 Apr 21 nicklas 240   /**
6200 08 Apr 21 nicklas 241     Get the name of the file.
6200 08 Apr 21 nicklas 242   */
6200 08 Apr 21 nicklas 243   public String getName()
6200 08 Apr 21 nicklas 244   {
6200 08 Apr 21 nicklas 245     return name;
6200 08 Apr 21 nicklas 246   }
6200 08 Apr 21 nicklas 247   
6734 09 May 22 nicklas 248   /**
6734 09 May 22 nicklas 249     Get the size of the JSON file. 
6734 09 May 22 nicklas 250     Note! Only available after downloadAndParse() 
6734 09 May 22 nicklas 251     method has been called.
6734 09 May 22 nicklas 252     @since 4.39
6734 09 May 22 nicklas 253   */
6734 09 May 22 nicklas 254   public long getSize()
6734 09 May 22 nicklas 255   {
6734 09 May 22 nicklas 256     return size;
6734 09 May 22 nicklas 257   }
6734 09 May 22 nicklas 258   
6734 09 May 22 nicklas 259   /**
6734 09 May 22 nicklas 260     Get the last modification timestampe of the JSON file. 
6734 09 May 22 nicklas 261     Note! Only available after downloadAndParse() method 
6734 09 May 22 nicklas 262     has been called.
6734 09 May 22 nicklas 263     @since 4.39
6734 09 May 22 nicklas 264   */
6734 09 May 22 nicklas 265   public long getLastModified()
6734 09 May 22 nicklas 266   {
6734 09 May 22 nicklas 267     return lastModified;
6734 09 May 22 nicklas 268   }
6734 09 May 22 nicklas 269   public Date getLastModifiedDate()
6734 09 May 22 nicklas 270   {
6734 09 May 22 nicklas 271     return new Date(lastModified);
6734 09 May 22 nicklas 272   }
6734 09 May 22 nicklas 273   
6200 08 Apr 21 nicklas 274   public boolean hasWarning()
6200 08 Apr 21 nicklas 275   {
6200 08 Apr 21 nicklas 276     return warningMessages.size() > 0;
6200 08 Apr 21 nicklas 277   }
6200 08 Apr 21 nicklas 278   public List<String> getWarningMessages()
6200 08 Apr 21 nicklas 279   {
6200 08 Apr 21 nicklas 280     return warningMessages;
6200 08 Apr 21 nicklas 281   }
6200 08 Apr 21 nicklas 282   public void addWarningMessage(String msg)
6200 08 Apr 21 nicklas 283   {
6200 08 Apr 21 nicklas 284     this.warningMessages.add(msg);
6200 08 Apr 21 nicklas 285   }
6573 07 Feb 22 nicklas 286   public void addWarningMessage(int index, String msg)
6573 07 Feb 22 nicklas 287   {
6573 07 Feb 22 nicklas 288     this.warningMessages.add(index, msg);
6573 07 Feb 22 nicklas 289   }
6200 08 Apr 21 nicklas 290   
6200 08 Apr 21 nicklas 291   public boolean hasError()
6200 08 Apr 21 nicklas 292   {
6200 08 Apr 21 nicklas 293     return errorMessages.size() > 0;
6200 08 Apr 21 nicklas 294   }
6200 08 Apr 21 nicklas 295   public List<String> getErrorMessages()
6200 08 Apr 21 nicklas 296   {
6200 08 Apr 21 nicklas 297     return errorMessages;
6200 08 Apr 21 nicklas 298   }
6200 08 Apr 21 nicklas 299   public void addErrorMessage(String msg)
6200 08 Apr 21 nicklas 300   {
6200 08 Apr 21 nicklas 301     this.errorMessages.add(msg);
6200 08 Apr 21 nicklas 302   }
6573 07 Feb 22 nicklas 303   public void addErrorMessage(int index, String msg)
6573 07 Feb 22 nicklas 304   {
6573 07 Feb 22 nicklas 305     this.errorMessages.add(index, msg);
6573 07 Feb 22 nicklas 306   }
6200 08 Apr 21 nicklas 307
6348 16 Aug 21 nicklas 308   public void clearAllMessages()
6348 16 Aug 21 nicklas 309   {
6348 16 Aug 21 nicklas 310     errorMessages.clear();
6348 16 Aug 21 nicklas 311     warningMessages.clear();
6348 16 Aug 21 nicklas 312     debugMessages.clear();
6348 16 Aug 21 nicklas 313   }
6348 16 Aug 21 nicklas 314   
6200 08 Apr 21 nicklas 315   public boolean hasDebug()
6200 08 Apr 21 nicklas 316   {
6200 08 Apr 21 nicklas 317     return debugMessages.size() > 0;
6200 08 Apr 21 nicklas 318   }
6200 08 Apr 21 nicklas 319   public List<String> getDebugMessages()
6200 08 Apr 21 nicklas 320   {
6200 08 Apr 21 nicklas 321     return debugMessages;
6200 08 Apr 21 nicklas 322   }
6200 08 Apr 21 nicklas 323   public void addDebugMessage(String msg)
6200 08 Apr 21 nicklas 324   {
6200 08 Apr 21 nicklas 325     this.debugMessages.add(msg);
6200 08 Apr 21 nicklas 326   }
6200 08 Apr 21 nicklas 327   
6200 08 Apr 21 nicklas 328   /**
6200 08 Apr 21 nicklas 329     Get meta-information about the JSON file.
6200 08 Apr 21 nicklas 330     If FASTQ files have been linked information about
6200 08 Apr 21 nicklas 331     them are included. If the JSON has been parsed error and
6200 08 Apr 21 nicklas 332     warning messages are also included.
6200 08 Apr 21 nicklas 333   */
6200 08 Apr 21 nicklas 334   public JSONObject asJSONObject()
6200 08 Apr 21 nicklas 335   {
6200 08 Apr 21 nicklas 336     JSONObject j = new JSONObject();
6200 08 Apr 21 nicklas 337     j.put("name", name);
6353 18 Aug 21 nicklas 338     j.put("size", size);
6353 18 Aug 21 nicklas 339     j.put("lastModified", Reggie.CONVERTER_DATETIME_TO_STRING_WITH_SEPARATOR.convert(new Date(lastModified)));
6895 25 Nov 22 nicklas 340     j.put("fullyValidated", fullyValidated);
6897 29 Nov 22 nicklas 341     j.put("flowCellId", flowCellId);
6911 30 Nov 22 nicklas 342     j.put("sequencingStartDate", sequencingStartDate);
6200 08 Apr 21 nicklas 343     if (fastqInfo != null)
6200 08 Apr 21 nicklas 344     {
6200 08 Apr 21 nicklas 345       JSONArray jsonFq = new JSONArray();
6200 08 Apr 21 nicklas 346       j.put("fastq", jsonFq);
6200 08 Apr 21 nicklas 347       if (fastqInfo.R1 != null) jsonFq.add(fastqInfo.R1.asJSONObject());
6200 08 Apr 21 nicklas 348       if (fastqInfo.R2 != null) jsonFq.add(fastqInfo.R2.asJSONObject());
6200 08 Apr 21 nicklas 349     }
6200 08 Apr 21 nicklas 350     
6474 04 Nov 21 nicklas 351     if (demuxInfo != null)
6474 04 Nov 21 nicklas 352     {
6474 04 Nov 21 nicklas 353       j.put("PF_READS", demuxInfo.pfReads);
6474 04 Nov 21 nicklas 354     }
6474 04 Nov 21 nicklas 355     
6200 08 Apr 21 nicklas 356     if (hasError())
6200 08 Apr 21 nicklas 357     {
6200 08 Apr 21 nicklas 358       JSONArray jsonErrors = new JSONArray();
6200 08 Apr 21 nicklas 359       jsonErrors.addAll(errorMessages);
6200 08 Apr 21 nicklas 360       j.put("errors", jsonErrors);
6200 08 Apr 21 nicklas 361     }
6200 08 Apr 21 nicklas 362     if (hasWarning())
6200 08 Apr 21 nicklas 363     {
6200 08 Apr 21 nicklas 364       JSONArray jsonWarnings = new JSONArray();
6200 08 Apr 21 nicklas 365       jsonWarnings.addAll(warningMessages);
6200 08 Apr 21 nicklas 366       j.put("warnings", jsonWarnings);
6200 08 Apr 21 nicklas 367     }
6200 08 Apr 21 nicklas 368     
6200 08 Apr 21 nicklas 369     return j;
6200 08 Apr 21 nicklas 370   }
6200 08 Apr 21 nicklas 371   
6200 08 Apr 21 nicklas 372   /**
6212 14 Apr 21 nicklas 373     Override the "Operator" (and similar) information in the JSON file
6212 14 Apr 21 nicklas 374     with the value specified here. This can be called before
6212 14 Apr 21 nicklas 375     or after parsing the JSON file.
6212 14 Apr 21 nicklas 376    */
6212 14 Apr 21 nicklas 377   public void setOperator(String operator)
6212 14 Apr 21 nicklas 378   {
6212 14 Apr 21 nicklas 379     this.operator = operator;
6994 20 Jan 23 nicklas 380     if (specimenInfo != null) specimenInfo.operator = operator;
6212 14 Apr 21 nicklas 381     if (dnaInfo != null) dnaInfo.operator = operator;
6212 14 Apr 21 nicklas 382     if (rnaInfo != null) rnaInfo.operator = operator;
6212 14 Apr 21 nicklas 383     if (flowThroughInfo != null) flowThroughInfo.operator = operator;
6212 14 Apr 21 nicklas 384     if (libInfo != null) libInfo.operator = operator;
6212 14 Apr 21 nicklas 385     if (poolInfo != null) poolInfo.operator = operator;
6212 14 Apr 21 nicklas 386     if (flowCellInfo != null) flowCellInfo.operator = operator;
6212 14 Apr 21 nicklas 387     if (seqRunInfo != null) seqRunInfo.operator = operator;
6212 14 Apr 21 nicklas 388   }
6212 14 Apr 21 nicklas 389   
6212 14 Apr 21 nicklas 390   /**
6200 08 Apr 21 nicklas 391     Download and parse the JSON file from the remote server.
6200 08 Apr 21 nicklas 392   */
6897 29 Nov 22 nicklas 393   public void downloadAndParse(RemoteSession session, String directory, boolean fullValidation, Set<String> fullValidateIfFlowCell, ImportContext ctx)
6200 08 Apr 21 nicklas 394   {
6210 14 Apr 21 nicklas 395     if (!directory.endsWith("/")) directory += "/";
6210 14 Apr 21 nicklas 396     String path = directory + name;
6200 08 Apr 21 nicklas 397
6200 08 Apr 21 nicklas 398     ByteArrayDownloadTarget download = new ByteArrayDownloadTarget(path);
6200 08 Apr 21 nicklas 399     try
6200 08 Apr 21 nicklas 400     {
6200 08 Apr 21 nicklas 401       session.downloadFile(path, download);
6353 18 Aug 21 nicklas 402       FileMetaData fmd = download.getMetadata();
6353 18 Aug 21 nicklas 403       size = fmd.getSize();
6353 18 Aug 21 nicklas 404       lastModified = fmd.getLastModifiedTime();
6200 08 Apr 21 nicklas 405     }
6200 08 Apr 21 nicklas 406     catch (Exception ex)
6200 08 Apr 21 nicklas 407     {
6200 08 Apr 21 nicklas 408       addErrorMessage("Could not download '"+ name + "': " + ex.getMessage());
6200 08 Apr 21 nicklas 409       return;
6200 08 Apr 21 nicklas 410     }
6200 08 Apr 21 nicklas 411     try
6200 08 Apr 21 nicklas 412     {
6209 13 Apr 21 nicklas 413       rawData = download.getString("UTF-8");
6209 13 Apr 21 nicklas 414       if (rawData == null || rawData.length() == 0)
6200 08 Apr 21 nicklas 415       {
6200 08 Apr 21 nicklas 416         addErrorMessage("Could not parse '"+name+"': File is empty");
6200 08 Apr 21 nicklas 417         return;
6200 08 Apr 21 nicklas 418       }
6974 13 Jan 23 nicklas 419       // Parse with our own ContainerFactory which allows us to inspect values
6974 13 Jan 23 nicklas 420       json = (JSONObject)new JSONParser().parse(rawData, new JsonContainerFactory()); 
6200 08 Apr 21 nicklas 421       
6701 26 Apr 22 nicklas 422       // If the top-level only has one entry we descend into that entry
6701 26 Apr 22 nicklas 423       // and use the key as SCANB_ID (unless it already exists at the lower level)
6701 26 Apr 22 nicklas 424       if (json.size()==1) 
6701 26 Apr 22 nicklas 425       {
6701 26 Apr 22 nicklas 426         Entry<String, Object> entry = json.entrySet().iterator().next();
6701 26 Apr 22 nicklas 427         json = (JSONObject)entry.getValue();
6701 26 Apr 22 nicklas 428         if (!json.containsKey("SCANB_ID"))
6701 26 Apr 22 nicklas 429         {
6701 26 Apr 22 nicklas 430           json.put("SCANB_ID", entry.getKey());
6701 26 Apr 22 nicklas 431         }
6701 26 Apr 22 nicklas 432       }
6701 26 Apr 22 nicklas 433       
6348 16 Aug 21 nicklas 434       mainInfo = new MainInfo(new JsonSection(this, "{}", json), ctx);
6734 09 May 22 nicklas 435       EndPoint endPoint = mainInfo.endPoint;
6341 29 Jun 21 nicklas 436       SampleIdType idType = mainInfo.idRef == null ? null : mainInfo.idRef.idType;
6341 29 Jun 21 nicklas 437       
6897 29 Nov 22 nicklas 438       // Validate additional JSON files if they are from the same flow cells
6897 29 Nov 22 nicklas 439       if (!fullValidation && fullValidateIfFlowCell != null)
6897 29 Nov 22 nicklas 440       {
6897 29 Nov 22 nicklas 441         try
6897 29 Nov 22 nicklas 442         {
6897 29 Nov 22 nicklas 443           flowCellId = (String)((JSONObject)json.get("FlowCell")).get("FlowCellID");
6897 29 Nov 22 nicklas 444           fullValidation = fullValidateIfFlowCell.contains(flowCellId);
6911 30 Nov 22 nicklas 445           sequencingStartDate = (String)((JSONObject)json.get("SequencingRun")).get("StartDate");
6897 29 Nov 22 nicklas 446         }
6897 29 Nov 22 nicklas 447         catch (RuntimeException ex)
6897 29 Nov 22 nicklas 448         {}
6897 29 Nov 22 nicklas 449       }
6897 29 Nov 22 nicklas 450       
6955 12 Dec 22 nicklas 451       fastqInfo = new FastqInfo(getSection(endPoint, "fastq"), ctx);
6955 12 Dec 22 nicklas 452       fastqInfo.loadFileInfo(ctx, session, directory, fullValidation);
6955 12 Dec 22 nicklas 453
6895 25 Nov 22 nicklas 454       if (fullValidation)
6341 29 Jun 21 nicklas 455       {
6895 25 Nov 22 nicklas 456         if (idType != SampleIdType.PRENORMALISED_RNA)
6895 25 Nov 22 nicklas 457         {
6895 25 Nov 22 nicklas 458           // TODO -- maybe some changes depending on idType
6895 25 Nov 22 nicklas 459           specimenInfo = new SpecimenInfo(getSection(endPoint, "Specimen"), mainInfo, ctx);
6895 25 Nov 22 nicklas 460           lysateInfo = new LysateInfo(getSection(endPoint, "Lysate"), specimenInfo, mainInfo);
6895 25 Nov 22 nicklas 461           rnaInfo = new RnaInfo(getSection(endPoint, "RNA"), specimenInfo, lysateInfo, mainInfo, ctx);
6895 25 Nov 22 nicklas 462           dnaInfo = new DnaInfo(getSection(endPoint, "DNA"), specimenInfo, lysateInfo, rnaInfo, mainInfo);
6895 25 Nov 22 nicklas 463           flowThroughInfo = new FlowThroughInfo(getSection(endPoint, "FlowThrough"), specimenInfo, lysateInfo, rnaInfo, mainInfo);
6895 25 Nov 22 nicklas 464         }
6960 13 Dec 22 nicklas 465         libInfo = new LibraryInfo(getSection(endPoint, "Library"), rnaInfo, fastqInfo, mainInfo, ctx);
6895 25 Nov 22 nicklas 466         poolInfo = new PoolInfo(getSection(endPoint, "Pool"), libInfo, mainInfo, ctx);
6960 13 Dec 22 nicklas 467         flowCellInfo = new FlowCellInfo(getSection(endPoint, "FlowCell"), fastqInfo, poolInfo, libInfo, mainInfo);
6897 29 Nov 22 nicklas 468         flowCellId = flowCellInfo.flowCellId;
6955 12 Dec 22 nicklas 469         seqRunInfo = new SequencingRunInfo(getSection(endPoint, "SequencingRun"), fastqInfo, flowCellInfo, poolInfo, mainInfo);
6911 30 Nov 22 nicklas 470         sequencingStartDate = Reggie.CONVERTER_DATE_TO_STRING_WITH_SEPARATOR.format(seqRunInfo.startDate);
6895 25 Nov 22 nicklas 471         demuxInfo = new DemuxInfo(getSection(endPoint, "DemuxedSequences"), getSection(endPoint, "MergedSequences"), mainInfo);
6895 25 Nov 22 nicklas 472         if (operator != null) setOperator(operator);
6895 25 Nov 22 nicklas 473         fullyValidated = fullValidation;
6341 29 Jun 21 nicklas 474       }
6895 25 Nov 22 nicklas 475       else
6895 25 Nov 22 nicklas 476       {
6895 25 Nov 22 nicklas 477         //addErrorMessage(0, "Full validation not done!");
6895 25 Nov 22 nicklas 478       }
6200 08 Apr 21 nicklas 479     }
6200 08 Apr 21 nicklas 480     catch (Exception ex)
6200 08 Apr 21 nicklas 481     {
6200 08 Apr 21 nicklas 482       addErrorMessage("Could not parse '"+name+"': " + ex.getMessage());
6200 08 Apr 21 nicklas 483       addErrorMessage(ThrowableUtil.stackTraceToString(ex));
6200 08 Apr 21 nicklas 484       return;
6200 08 Apr 21 nicklas 485     }
6200 08 Apr 21 nicklas 486   }
6200 08 Apr 21 nicklas 487   
6210 14 Apr 21 nicklas 488   /**
6210 14 Apr 21 nicklas 489     Delete the JSON file from the remote server.
7226 01 Jun 23 nicklas 490     @return An error message if the deletion failed, null otherwise
6210 14 Apr 21 nicklas 491   */
7226 01 Jun 23 nicklas 492   public String deleteFrom(RemoteSession session, String directory)
6210 14 Apr 21 nicklas 493   {
6210 14 Apr 21 nicklas 494     if (!directory.endsWith("/")) directory += "/";
6210 14 Apr 21 nicklas 495     String path = directory + name;
6210 14 Apr 21 nicklas 496
6210 14 Apr 21 nicklas 497     UploadSource upload = new StringUploadSource(name, rawData);
6210 14 Apr 21 nicklas 498     try
6210 14 Apr 21 nicklas 499     {
6210 14 Apr 21 nicklas 500       session.executeCmd("rm -f " + path, 5).throwExceptionIfNonZeroExitStatus();
6210 14 Apr 21 nicklas 501     }
6210 14 Apr 21 nicklas 502     catch (Exception ex)
6210 14 Apr 21 nicklas 503     {
7226 01 Jun 23 nicklas 504       String msg = "Could not delete '"+ path + "': " + ex.getMessage();
7226 01 Jun 23 nicklas 505       addErrorMessage(msg);
7226 01 Jun 23 nicklas 506       return msg;
6210 14 Apr 21 nicklas 507     }
7226 01 Jun 23 nicklas 508     return null;
6210 14 Apr 21 nicklas 509   }
6209 13 Apr 21 nicklas 510   
6210 14 Apr 21 nicklas 511   /**
6210 14 Apr 21 nicklas 512     Save the JSON file to the remote server in the given directory.
7226 01 Jun 23 nicklas 513     @return An error message if the save failed, null otherwise
6210 14 Apr 21 nicklas 514   */
7226 01 Jun 23 nicklas 515   public String saveTo(RemoteSession session, String directory)
6209 13 Apr 21 nicklas 516   {
6210 14 Apr 21 nicklas 517     if (!directory.endsWith("/")) directory += "/";
6210 14 Apr 21 nicklas 518     String path = directory + name;
6209 13 Apr 21 nicklas 519
6209 13 Apr 21 nicklas 520     UploadSource upload = new StringUploadSource(name, rawData);
6209 13 Apr 21 nicklas 521     try
6209 13 Apr 21 nicklas 522     {
6210 14 Apr 21 nicklas 523       session.executeCmd("mkdir -p " + directory, 5).throwExceptionIfNonZeroExitStatus();
6955 12 Dec 22 nicklas 524       session.uploadFile(upload, path, new FilePermission(FilePermission.READ, FilePermission.READ, FilePermission.NONE));
6209 13 Apr 21 nicklas 525     }
6209 13 Apr 21 nicklas 526     catch (Exception ex)
6209 13 Apr 21 nicklas 527     {
7226 01 Jun 23 nicklas 528       String msg = "Could not save to '"+ path + "': " + ex.getMessage();
7226 01 Jun 23 nicklas 529       addErrorMessage(msg);
7226 01 Jun 23 nicklas 530       return msg;
6209 13 Apr 21 nicklas 531     }
7226 01 Jun 23 nicklas 532     return null;
6209 13 Apr 21 nicklas 533   }
6209 13 Apr 21 nicklas 534   
6734 09 May 22 nicklas 535   public JsonSection getSection(EndPoint endPoint, String key)
6200 08 Apr 21 nicklas 536   {
6200 08 Apr 21 nicklas 537     JSONObject jsonSect = (JSONObject)json.get(key);
6200 08 Apr 21 nicklas 538     if (jsonSect == null)
6200 08 Apr 21 nicklas 539     {
6734 09 May 22 nicklas 540       if (endPoint.needSection(key))
6734 09 May 22 nicklas 541       {
6734 09 May 22 nicklas 542         addErrorMessage("Section is missing: "+key);
6734 09 May 22 nicklas 543       }
6734 09 May 22 nicklas 544       else
6734 09 May 22 nicklas 545       {
6734 09 May 22 nicklas 546         //addWarningMessage("Section is missing: "+key);
6734 09 May 22 nicklas 547       }
6200 08 Apr 21 nicklas 548     }
6200 08 Apr 21 nicklas 549     return jsonSect == null ? null : new JsonSection(this, key, jsonSect);
6200 08 Apr 21 nicklas 550   }
6200 08 Apr 21 nicklas 551   
6341 29 Jun 21 nicklas 552   public MainInfo getMain()
6341 29 Jun 21 nicklas 553   {
6341 29 Jun 21 nicklas 554     return mainInfo;
6341 29 Jun 21 nicklas 555   }
6341 29 Jun 21 nicklas 556   
6217 19 Apr 21 nicklas 557   public SpecimenInfo getSpecimen()
6217 19 Apr 21 nicklas 558   {
6217 19 Apr 21 nicklas 559     return specimenInfo;
6217 19 Apr 21 nicklas 560   }
6217 19 Apr 21 nicklas 561   
6207 12 Apr 21 nicklas 562   public LysateInfo getLysate()
6207 12 Apr 21 nicklas 563   {
6207 12 Apr 21 nicklas 564     return lysateInfo;
6207 12 Apr 21 nicklas 565   }
6207 12 Apr 21 nicklas 566   
6207 12 Apr 21 nicklas 567   public RnaInfo getRna()
6207 12 Apr 21 nicklas 568   {
6207 12 Apr 21 nicklas 569     return rnaInfo;
6207 12 Apr 21 nicklas 570   }
6207 12 Apr 21 nicklas 571   
6207 12 Apr 21 nicklas 572   public DnaInfo getDna()
6207 12 Apr 21 nicklas 573   {
6207 12 Apr 21 nicklas 574     return dnaInfo;
6207 12 Apr 21 nicklas 575   }
6207 12 Apr 21 nicklas 576   
6207 12 Apr 21 nicklas 577   public FlowThroughInfo getFlowThroughInfo()
6207 12 Apr 21 nicklas 578   {
6207 12 Apr 21 nicklas 579     return flowThroughInfo;
6207 12 Apr 21 nicklas 580   }
6207 12 Apr 21 nicklas 581   
6200 08 Apr 21 nicklas 582   public LibraryInfo getLibrary()
6200 08 Apr 21 nicklas 583   {
6200 08 Apr 21 nicklas 584     return libInfo;
6200 08 Apr 21 nicklas 585   }
6200 08 Apr 21 nicklas 586   
6200 08 Apr 21 nicklas 587   public PoolInfo getPool()
6200 08 Apr 21 nicklas 588   {
6200 08 Apr 21 nicklas 589     return poolInfo;
6200 08 Apr 21 nicklas 590   }
6200 08 Apr 21 nicklas 591   
6201 09 Apr 21 nicklas 592   public FlowCellInfo getFlowCell()
6201 09 Apr 21 nicklas 593   {
6201 09 Apr 21 nicklas 594     return flowCellInfo;
6201 09 Apr 21 nicklas 595   }
6201 09 Apr 21 nicklas 596   
6201 09 Apr 21 nicklas 597   public SequencingRunInfo getSequencingRun()
6201 09 Apr 21 nicklas 598   {
6201 09 Apr 21 nicklas 599     return seqRunInfo;
6201 09 Apr 21 nicklas 600   }
6201 09 Apr 21 nicklas 601   
6203 09 Apr 21 nicklas 602   public DemuxInfo getDemuxInfo()
6203 09 Apr 21 nicklas 603   {
6203 09 Apr 21 nicklas 604     return demuxInfo;
6203 09 Apr 21 nicklas 605   }
6203 09 Apr 21 nicklas 606   
6209 13 Apr 21 nicklas 607   public FastqInfo getFastqInfo()
6200 08 Apr 21 nicklas 608   {
6200 08 Apr 21 nicklas 609     return fastqInfo;
6200 08 Apr 21 nicklas 610   }
6974 13 Jan 23 nicklas 611   
6974 13 Jan 23 nicklas 612   /**
6974 13 Jan 23 nicklas 613     Our factory for creating JSON objects and arrays. With this we can create special
6974 13 Jan 23 nicklas 614     implementation that can inspect values before they are inserted. The only use case 
6974 13 Jan 23 nicklas 615     so far is that we should treat the special string "(Fritext)" as a null value.
6974 13 Jan 23 nicklas 616   */
6974 13 Jan 23 nicklas 617   static class JsonContainerFactory
6974 13 Jan 23 nicklas 618     implements ContainerFactory
6974 13 Jan 23 nicklas 619   {
6974 13 Jan 23 nicklas 620
6974 13 Jan 23 nicklas 621     @SuppressWarnings("serial")
6974 13 Jan 23 nicklas 622     @Override
6974 13 Jan 23 nicklas 623     public Map<String, Object> createObjectContainer() 
6974 13 Jan 23 nicklas 624     {
6974 13 Jan 23 nicklas 625       return new JSONObject()
6974 13 Jan 23 nicklas 626       {
6974 13 Jan 23 nicklas 627         @Override
6974 13 Jan 23 nicklas 628         public Object put(String key, Object value) 
6974 13 Jan 23 nicklas 629         {
6974 13 Jan 23 nicklas 630           if ("(Fritext)".equals(value)) value = null;
6974 13 Jan 23 nicklas 631           return super.put(key, value);
6974 13 Jan 23 nicklas 632         }
6974 13 Jan 23 nicklas 633       };
6974 13 Jan 23 nicklas 634     }
6974 13 Jan 23 nicklas 635
6974 13 Jan 23 nicklas 636     @Override
6974 13 Jan 23 nicklas 637     public List<Object> creatArrayContainer() 
6974 13 Jan 23 nicklas 638     {
6974 13 Jan 23 nicklas 639       return new JSONArray();
6974 13 Jan 23 nicklas 640     }
6974 13 Jan 23 nicklas 641     
6974 13 Jan 23 nicklas 642   }
6200 08 Apr 21 nicklas 643 }