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

Code
Comments
Other
Rev Date Author Line
7267 21 Jun 23 nicklas 1 package net.sf.basedb.reggie.servlet;
7267 21 Jun 23 nicklas 2
7267 21 Jun 23 nicklas 3 import java.io.IOException;
7267 21 Jun 23 nicklas 4 import java.util.ArrayList;
7313 29 Aug 23 nicklas 5 import java.util.Arrays;
7290 18 Aug 23 nicklas 6 import java.util.LinkedHashSet;
7267 21 Jun 23 nicklas 7 import java.util.List;
7290 18 Aug 23 nicklas 8 import java.util.Set;
7267 21 Jun 23 nicklas 9
7267 21 Jun 23 nicklas 10 import javax.servlet.ServletException;
7267 21 Jun 23 nicklas 11 import javax.servlet.http.HttpServlet;
7267 21 Jun 23 nicklas 12 import javax.servlet.http.HttpServletRequest;
7267 21 Jun 23 nicklas 13 import javax.servlet.http.HttpServletResponse;
7267 21 Jun 23 nicklas 14
7267 21 Jun 23 nicklas 15 import org.json.simple.JSONArray;
7267 21 Jun 23 nicklas 16 import org.json.simple.JSONObject;
7267 21 Jun 23 nicklas 17
7267 21 Jun 23 nicklas 18 import net.sf.basedb.core.ItemList;
7267 21 Jun 23 nicklas 19 import net.sf.basedb.core.ItemNotFoundException;
7293 22 Aug 23 nicklas 20 import net.sf.basedb.core.BasicItem;
7269 26 Jun 23 nicklas 21 import net.sf.basedb.core.BioSource;
7267 21 Jun 23 nicklas 22 import net.sf.basedb.core.DbControl;
7267 21 Jun 23 nicklas 23 import net.sf.basedb.core.DerivedBioAssay;
7289 18 Aug 23 nicklas 24 import net.sf.basedb.core.Item;
7267 21 Jun 23 nicklas 25 import net.sf.basedb.core.ItemQuery;
7268 22 Jun 23 nicklas 26 import net.sf.basedb.core.Job;
7267 21 Jun 23 nicklas 27 import net.sf.basedb.core.SessionControl;
7267 21 Jun 23 nicklas 28 import net.sf.basedb.core.Software;
7293 22 Aug 23 nicklas 29 import net.sf.basedb.core.Trashcan;
7289 18 Aug 23 nicklas 30 import net.sf.basedb.core.query.Annotations;
7289 18 Aug 23 nicklas 31 import net.sf.basedb.core.query.Expressions;
7267 21 Jun 23 nicklas 32 import net.sf.basedb.core.query.Hql;
7313 29 Aug 23 nicklas 33 import net.sf.basedb.core.query.IdListRestriction;
7267 21 Jun 23 nicklas 34 import net.sf.basedb.core.query.Orders;
7289 18 Aug 23 nicklas 35 import net.sf.basedb.core.query.Restrictions;
7267 21 Jun 23 nicklas 36 import net.sf.basedb.core.snapshot.SnapshotManager;
7268 22 Jun 23 nicklas 37 import net.sf.basedb.opengrid.JobDefinition;
7267 21 Jun 23 nicklas 38 import net.sf.basedb.opengrid.OpenGridCluster;
7341 11 Sep 23 nicklas 39 import net.sf.basedb.opengrid.config.BatchConfig;
7267 21 Jun 23 nicklas 40 import net.sf.basedb.opengrid.service.OpenGridService;
7267 21 Jun 23 nicklas 41 import net.sf.basedb.reggie.JsonUtil;
7267 21 Jun 23 nicklas 42 import net.sf.basedb.reggie.Reggie;
7293 22 Aug 23 nicklas 43 import net.sf.basedb.reggie.activity.ActivityDef;
7267 21 Jun 23 nicklas 44 import net.sf.basedb.reggie.counter.CounterService;
7267 21 Jun 23 nicklas 45 import net.sf.basedb.reggie.dao.AlignedSequences;
7267 21 Jun 23 nicklas 46 import net.sf.basedb.reggie.dao.Annotationtype;
7267 21 Jun 23 nicklas 47 import net.sf.basedb.reggie.dao.BiomaterialList;
7289 18 Aug 23 nicklas 48 import net.sf.basedb.reggie.dao.CopyNumber;
7269 26 Jun 23 nicklas 49 import net.sf.basedb.reggie.dao.Patient;
7269 26 Jun 23 nicklas 50 import net.sf.basedb.reggie.dao.Pipeline;
7267 21 Jun 23 nicklas 51 import net.sf.basedb.reggie.dao.ReggieRole;
7267 21 Jun 23 nicklas 52 import net.sf.basedb.reggie.dao.Subtype;
7406 08 Nov 23 nicklas 53 import net.sf.basedb.reggie.dao.TumorNormalPair;
7268 22 Jun 23 nicklas 54 import net.sf.basedb.reggie.grid.AscatJobCreator;
7341 11 Sep 23 nicklas 55 import net.sf.basedb.reggie.grid.AscatJobCreator.AllelicImbalanceTest;
7268 22 Jun 23 nicklas 56 import net.sf.basedb.reggie.grid.ScriptUtil;
7267 21 Jun 23 nicklas 57 import net.sf.basedb.util.Values;
7267 21 Jun 23 nicklas 58 import net.sf.basedb.util.error.ThrowableUtil;
7267 21 Jun 23 nicklas 59
7267 21 Jun 23 nicklas 60
7267 21 Jun 23 nicklas 61 public class AscatServlet 
7267 21 Jun 23 nicklas 62   extends HttpServlet 
7267 21 Jun 23 nicklas 63 {
7267 21 Jun 23 nicklas 64
7268 22 Jun 23 nicklas 65   private static final long serialVersionUID = -3992456639948968963L;
7268 22 Jun 23 nicklas 66
7341 11 Sep 23 nicklas 67   /**
7341 11 Sep 23 nicklas 68     Variable for storing the earliest allowed start time for the next ASCAT job.
7341 11 Sep 23 nicklas 69     We do not want to start too many ASCAT jobs at the same time since copying
7341 11 Sep 23 nicklas 70     the BAM files to the local node will overload the server were they are stored.
7341 11 Sep 23 nicklas 71   */
7341 11 Sep 23 nicklas 72   private static long NEXT_START_TIME = 0;
7341 11 Sep 23 nicklas 73
7341 11 Sep 23 nicklas 74   
7267 21 Jun 23 nicklas 75   public AscatServlet()
7267 21 Jun 23 nicklas 76   {}
7267 21 Jun 23 nicklas 77
7267 21 Jun 23 nicklas 78   @Override
7267 21 Jun 23 nicklas 79   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
7267 21 Jun 23 nicklas 80     throws ServletException, IOException 
7267 21 Jun 23 nicklas 81   {
7267 21 Jun 23 nicklas 82     String cmd = req.getParameter("cmd");
7267 21 Jun 23 nicklas 83     JsonUtil.setJsonResponseHeaders(resp);
7267 21 Jun 23 nicklas 84     
7267 21 Jun 23 nicklas 85     JSONObject json = new JSONObject();
7267 21 Jun 23 nicklas 86     json.put("status", "ok");
7267 21 Jun 23 nicklas 87     
7267 21 Jun 23 nicklas 88     final SessionControl sc = Reggie.getSessionControl(req);
7267 21 Jun 23 nicklas 89     DbControl dc = null;
7267 21 Jun 23 nicklas 90     try
7267 21 Jun 23 nicklas 91     {
7267 21 Jun 23 nicklas 92       if ("GetAlignedSequencesForAscatAnalysis".equals(cmd))
7267 21 Jun 23 nicklas 93       {
7267 21 Jun 23 nicklas 94         dc = sc.newDbControl(":Start ASCAT analysis");
7267 21 Jun 23 nicklas 95         
7267 21 Jun 23 nicklas 96         List<AlignedSequences> list = null;
7267 21 Jun 23 nicklas 97         String items = Values.getStringOrNull(req.getParameter("items"));
7267 21 Jun 23 nicklas 98         if (items == null)
7267 21 Jun 23 nicklas 99         {
7267 21 Jun 23 nicklas 100           ItemList ascatPipeline = BiomaterialList.ASCAT_PIPELINE.load(dc);
7267 21 Jun 23 nicklas 101           ItemQuery<DerivedBioAssay> query = ascatPipeline.getMembers();
7267 21 Jun 23 nicklas 102           query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
7267 21 Jun 23 nicklas 103           Subtype.ALIGNED_SEQUENCES.addFilter(dc, query);
7267 21 Jun 23 nicklas 104           query.order(Orders.asc(Hql.property("name")));
7269 26 Jun 23 nicklas 105           query.setMaxResults(50);
7267 21 Jun 23 nicklas 106           list = AlignedSequences.toList(query.list(dc));
7267 21 Jun 23 nicklas 107         }
7267 21 Jun 23 nicklas 108         else
7267 21 Jun 23 nicklas 109         {
7267 21 Jun 23 nicklas 110           Integer[] ids = Values.getInt(items.split(","));
7267 21 Jun 23 nicklas 111           list = new ArrayList<AlignedSequences>();
7267 21 Jun 23 nicklas 112           for (Integer id : ids)
7267 21 Jun 23 nicklas 113           {
7267 21 Jun 23 nicklas 114             list.add(AlignedSequences.getById(dc, id));
7267 21 Jun 23 nicklas 115           }
7267 21 Jun 23 nicklas 116         }
7267 21 Jun 23 nicklas 117         SnapshotManager manager = new SnapshotManager();
7267 21 Jun 23 nicklas 118         JSONArray jsonAlignedSequences = new JSONArray();
7267 21 Jun 23 nicklas 119         for (AlignedSequences as : list)
7267 21 Jun 23 nicklas 120         {
7267 21 Jun 23 nicklas 121           as.loadAnnotations(dc, "pipeline", Annotationtype.PIPELINE, null);
7267 21 Jun 23 nicklas 122           as.loadAnnotations(dc, manager, "AutoProcess", Annotationtype.AUTO_PROCESSING, null);
7267 21 Jun 23 nicklas 123           as.loadDoNotUseAnnotations(dc, manager);
7269 26 Jun 23 nicklas 124           
7269 26 Jun 23 nicklas 125           Patient patient = Patient.get((BioSource)as.findSingleParent(dc, Subtype.PATIENT));
7269 26 Jun 23 nicklas 126           as.setAnnotation("patient", patient.asJSONObject());
7269 26 Jun 23 nicklas 127           
7269 26 Jun 23 nicklas 128           JSONArray jsonNormals = new JSONArray();
7269 26 Jun 23 nicklas 129           ItemQuery<DerivedBioAssay> query = patient.findChildItems(dc, Subtype.ALIGNED_SEQUENCES);
7269 26 Jun 23 nicklas 130           Pipeline.DNA_NORMAL_WGS.addFilter(dc, query);
7294 23 Aug 23 nicklas 131           query.restrict(Restrictions.neq(Hql.property("id"), Expressions.integer(as.getId())));
7269 26 Jun 23 nicklas 132           query.order(Orders.asc(Hql.property("name")));
7269 26 Jun 23 nicklas 133           for (DerivedBioAssay ch : query.list(dc))
7269 26 Jun 23 nicklas 134           {
7269 26 Jun 23 nicklas 135             AlignedSequences normal = AlignedSequences.get(ch);
7269 26 Jun 23 nicklas 136             normal.loadDoNotUseAnnotations(dc, manager);
7269 26 Jun 23 nicklas 137             jsonNormals.add(normal.asJSONObject());
7269 26 Jun 23 nicklas 138           }
7269 26 Jun 23 nicklas 139           as.setAnnotation("normals", jsonNormals);
7267 21 Jun 23 nicklas 140           jsonAlignedSequences.add(as.asJSONObject());
7267 21 Jun 23 nicklas 141         }
7267 21 Jun 23 nicklas 142         json.put("alignedSequences", jsonAlignedSequences);
7267 21 Jun 23 nicklas 143       }
7290 18 Aug 23 nicklas 144       else if ("LoadExistingResults".equals(cmd))
7290 18 Aug 23 nicklas 145       {
7290 18 Aug 23 nicklas 146         dc = sc.newDbControl(":Load existing ASCAT analysis");
7290 18 Aug 23 nicklas 147         
7290 18 Aug 23 nicklas 148         int tumorId = Values.getInt(req.getParameter("tumorId"));
7290 18 Aug 23 nicklas 149         int normalId = Values.getInt(req.getParameter("normalId"));
7290 18 Aug 23 nicklas 150          
7290 18 Aug 23 nicklas 151         AlignedSequences tumor = AlignedSequences.getById(dc, tumorId);
7290 18 Aug 23 nicklas 152         AlignedSequences normal = AlignedSequences.getById(dc, normalId);
7290 18 Aug 23 nicklas 153         
7290 18 Aug 23 nicklas 154         ItemQuery<DerivedBioAssay> query = DerivedBioAssay.getQuery();
7290 18 Aug 23 nicklas 155         query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
7290 18 Aug 23 nicklas 156         Subtype.COPY_NUMBER.addFilter(dc, query);
7290 18 Aug 23 nicklas 157         // The job must be an ASCAT job and it must be ended
7290 18 Aug 23 nicklas 158         query.join(Hql.innerJoin("job", "jb"));
7290 18 Aug 23 nicklas 159         Subtype.ASCAT_JOB.addFilter(dc, query, "jb");
7290 18 Aug 23 nicklas 160         query.restrict(Restrictions.neq(Hql.property("jb", "ended"), null));
7291 21 Aug 23 nicklas 161         // TODO -- filter on job status or some annotation?
7290 18 Aug 23 nicklas 162         // Join parent items
7290 18 Aug 23 nicklas 163         query.joinPermanent(Hql.innerJoin("parents", "p"));
7290 18 Aug 23 nicklas 164         query.restrict(Restrictions.eq(Hql.alias("p"), Hql.entityParameter("parent", Item.DERIVEDBIOASSAY)));
7290 18 Aug 23 nicklas 165         query.order(Orders.asc(Hql.property("name")));
7290 18 Aug 23 nicklas 166
7290 18 Aug 23 nicklas 167         Set<DerivedBioAssay> results = new LinkedHashSet<>();
7290 18 Aug 23 nicklas 168         query.setEntityParameter("parent", tumor.getItem());
7290 18 Aug 23 nicklas 169         results.addAll(query.list(dc));
7290 18 Aug 23 nicklas 170         query.setEntityParameter("parent", normal.getItem());
7290 18 Aug 23 nicklas 171         results.retainAll(query.list(dc));
7290 18 Aug 23 nicklas 172         
7290 18 Aug 23 nicklas 173         List<CopyNumber> list = CopyNumber.toList(results);
7290 18 Aug 23 nicklas 174         SnapshotManager manager = new SnapshotManager();
7290 18 Aug 23 nicklas 175         JSONArray jsonAscat = new JSONArray();
7290 18 Aug 23 nicklas 176         for (CopyNumber cn : list)
7290 18 Aug 23 nicklas 177         {
7290 18 Aug 23 nicklas 178           cn.loadAnnotations(dc, manager, "PIPELINE", Annotationtype.PIPELINE, null);
7290 18 Aug 23 nicklas 179           cn.loadAnnotations(dc, manager, "DataFilesFolder", Annotationtype.DATA_FILES_FOLDER, null);
7293 22 Aug 23 nicklas 180           cn.loadAnnotations(dc, manager, "AscatResult", Annotationtype.ASCAT_RESULT, null);
7290 18 Aug 23 nicklas 181           cn.loadAnnotations(dc, manager, "ImbalanceTest", Annotationtype.IMBALANCE_TEST, null);
7341 11 Sep 23 nicklas 182           cn.loadAnnotations(dc, manager, "Penalty", Annotationtype.PENALTY, null);
7341 11 Sep 23 nicklas 183           cn.loadAnnotations(dc, manager, "MinDepth", Annotationtype.MIN_DEPTH, null);
7290 18 Aug 23 nicklas 184           cn.loadAnnotations(dc, manager, "TauManual", Annotationtype.TAU_MANUAL, null);
7290 18 Aug 23 nicklas 185           cn.loadAnnotations(dc, manager, "RhoManual", Annotationtype.RHO_MANUAL, null);
7290 18 Aug 23 nicklas 186           cn.loadAnnotations(dc, manager, "PsiManual", Annotationtype.PSI_MANUAL, null);
7290 18 Aug 23 nicklas 187           cn.loadAnnotations(dc, manager, "Ploidy", Annotationtype.PLOIDY, null);
7290 18 Aug 23 nicklas 188           cn.loadAnnotations(dc, manager, "Purity", Annotationtype.PURITY, null);
7290 18 Aug 23 nicklas 189           cn.loadAnnotations(dc, manager, "GoodnessOfFit", Annotationtype.GOODNESS_OF_FIT, null);
7290 18 Aug 23 nicklas 190           cn.loadAnnotations(dc, manager, "NormalContamination", Annotationtype.NORMAL_CONTAMINATION, null);
7341 11 Sep 23 nicklas 191           cn.loadAnnotations(dc, manager, "NonAberrant", Annotationtype.NON_ABERRANT, null);
7293 22 Aug 23 nicklas 192           cn.setAnnotation("comment", cn.getItem().getDescription());
7290 18 Aug 23 nicklas 193           
7290 18 Aug 23 nicklas 194           // Load some images
7290 18 Aug 23 nicklas 195           cn.setAnnotation("sunrisePlot", JsonUtil.loadLinkedItem(dc, cn.getItem(), "sunrise.png", Item.FILE, null));
7290 18 Aug 23 nicklas 196           cn.setAnnotation("segmentationPlot", JsonUtil.loadLinkedItem(dc, cn.getItem(), "ASPCF.png", Item.FILE, null));
7290 18 Aug 23 nicklas 197           cn.setAnnotation("ascatPlot", JsonUtil.loadLinkedItem(dc, cn.getItem(), "ASCATprofile.png", Item.FILE, null));
7341 11 Sep 23 nicklas 198           cn.setAnnotation("imbalanceTest", JsonUtil.loadLinkedItem(dc, cn.getItem(), "imbalance.test.txt", Item.FILE, null));
7405 08 Nov 23 nicklas 199           cn.setAnnotation("stats", JsonUtil.loadLinkedItem(dc, cn.getItem(), "stats.txt", Item.FILE, null));
7290 18 Aug 23 nicklas 200
7290 18 Aug 23 nicklas 201           jsonAscat.add(cn.asJSONObject());
7290 18 Aug 23 nicklas 202         }
7290 18 Aug 23 nicklas 203         json.put("tumor", tumor.asJSONObject());
7290 18 Aug 23 nicklas 204         json.put("normal", normal.asJSONObject());
7290 18 Aug 23 nicklas 205         json.put("ascatItems", jsonAscat);
7290 18 Aug 23 nicklas 206       }
7289 18 Aug 23 nicklas 207       else if ("GetUnconfirmedAscatItems".equals(cmd))
7289 18 Aug 23 nicklas 208       {
7289 18 Aug 23 nicklas 209         dc = sc.newDbControl(":Confirm ASCAT analysis");
7313 29 Aug 23 nicklas 210         
7313 29 Aug 23 nicklas 211         String selected = req.getParameter("items");
7289 18 Aug 23 nicklas 212         ItemQuery<DerivedBioAssay> query = DerivedBioAssay.getQuery();
7289 18 Aug 23 nicklas 213         query.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
7289 18 Aug 23 nicklas 214         Subtype.COPY_NUMBER.addFilter(dc, query);
7313 29 Aug 23 nicklas 215         boolean loadAllDetails = false;
7313 29 Aug 23 nicklas 216         if (selected != null)
7313 29 Aug 23 nicklas 217         {
7313 29 Aug 23 nicklas 218           loadAllDetails = true;
7313 29 Aug 23 nicklas 219           query.restrict(new IdListRestriction("id", Arrays.asList(Values.getInt(selected.split(",")))));
7313 29 Aug 23 nicklas 220         }
7313 29 Aug 23 nicklas 221         else
7313 29 Aug 23 nicklas 222         {
7313 29 Aug 23 nicklas 223           // The job must be an ASCAT job and it must be ended
7313 29 Aug 23 nicklas 224           query.join(Hql.innerJoin("job", "jb"));
7313 29 Aug 23 nicklas 225           Subtype.ASCAT_JOB.addFilter(dc, query, "jb");
7313 29 Aug 23 nicklas 226           query.restrict(Restrictions.neq(Hql.property("jb", "ended"), null));
7313 29 Aug 23 nicklas 227           // Must NOT have a ANALYSIS_RESULT annotation
7313 29 Aug 23 nicklas 228           query.join(Annotations.leftJoin(null, Annotationtype.ANALYSIS_RESULT.load(dc), "ar"));
7313 29 Aug 23 nicklas 229           query.restrict(Restrictions.eq(Hql.alias("ar"), null));
7313 29 Aug 23 nicklas 230           // Ignore if AutoProcess==AutoConfirm
7313 29 Aug 23 nicklas 231           query.join(Annotations.leftJoin(null, Annotationtype.AUTO_PROCESSING.load(dc), "ap"));
7313 29 Aug 23 nicklas 232           query.restrict(
7313 29 Aug 23 nicklas 233               Restrictions.or(
7313 29 Aug 23 nicklas 234                 Restrictions.neq(Hql.alias("ap"), Expressions.string("AutoConfirm")),
7313 29 Aug 23 nicklas 235                 Restrictions.eq(Hql.alias("ap"), null)
7313 29 Aug 23 nicklas 236               ));
7313 29 Aug 23 nicklas 237         }
7289 18 Aug 23 nicklas 238         query.order(Orders.asc(Hql.property("name")));
7289 18 Aug 23 nicklas 239         
7289 18 Aug 23 nicklas 240         SnapshotManager manager = new SnapshotManager();
7290 18 Aug 23 nicklas 241         JSONArray jsonAscat = new JSONArray();
7289 18 Aug 23 nicklas 242         List<CopyNumber> list = CopyNumber.toList(query.list(dc));
7289 18 Aug 23 nicklas 243         for (CopyNumber cn : list)
7289 18 Aug 23 nicklas 244         {
7313 29 Aug 23 nicklas 245           AlignedSequences tumor = cn.getTumorAlignment(dc);
7313 29 Aug 23 nicklas 246           cn.setAnnotation("tumor", tumor.asJSONObject());
7313 29 Aug 23 nicklas 247           cn.loadAnnotations(dc, manager, "AscatResult", Annotationtype.ASCAT_RESULT, null);
7289 18 Aug 23 nicklas 248           
7289 18 Aug 23 nicklas 249           // Load job information
7289 18 Aug 23 nicklas 250           Job job = cn.getItem().getJob();
7289 18 Aug 23 nicklas 251           JSONObject jsonJob = JsonUtil.getJobAsJSON(job);
7289 18 Aug 23 nicklas 252           cn.setAnnotation("job", jsonJob);
7289 18 Aug 23 nicklas 253
7289 18 Aug 23 nicklas 254           boolean debug = Boolean.TRUE.equals(job.getParameterValue("debug"));
7289 18 Aug 23 nicklas 255           jsonJob.put("debug", debug);
7313 29 Aug 23 nicklas 256           
7313 29 Aug 23 nicklas 257           if (loadAllDetails)
7313 29 Aug 23 nicklas 258           {
7313 29 Aug 23 nicklas 259             cn.loadAnnotations(dc, manager, "PIPELINE", Annotationtype.PIPELINE, null);
7313 29 Aug 23 nicklas 260             cn.loadAnnotations(dc, manager, "DataFilesFolder", Annotationtype.DATA_FILES_FOLDER, null);
7313 29 Aug 23 nicklas 261             cn.loadAnnotations(dc, manager, "ImbalanceTest", Annotationtype.IMBALANCE_TEST, null);
7341 11 Sep 23 nicklas 262             cn.loadAnnotations(dc, manager, "Penalty", Annotationtype.PENALTY, null);
7341 11 Sep 23 nicklas 263             cn.loadAnnotations(dc, manager, "MinDepth", Annotationtype.MIN_DEPTH, null);
7313 29 Aug 23 nicklas 264             cn.loadAnnotations(dc, manager, "TauManual", Annotationtype.TAU_MANUAL, null);
7313 29 Aug 23 nicklas 265             cn.loadAnnotations(dc, manager, "RhoManual", Annotationtype.RHO_MANUAL, null);
7313 29 Aug 23 nicklas 266             cn.loadAnnotations(dc, manager, "PsiManual", Annotationtype.PSI_MANUAL, null);
7313 29 Aug 23 nicklas 267             cn.loadAnnotations(dc, manager, "Ploidy", Annotationtype.PLOIDY, null);
7313 29 Aug 23 nicklas 268             cn.loadAnnotations(dc, manager, "Purity", Annotationtype.PURITY, null);
7313 29 Aug 23 nicklas 269             cn.loadAnnotations(dc, manager, "GoodnessOfFit", Annotationtype.GOODNESS_OF_FIT, null);
7313 29 Aug 23 nicklas 270             cn.loadAnnotations(dc, manager, "NormalContamination", Annotationtype.NORMAL_CONTAMINATION, null);
7341 11 Sep 23 nicklas 271             cn.loadAnnotations(dc, manager, "NonAberrant", Annotationtype.NON_ABERRANT, null);
7313 29 Aug 23 nicklas 272             cn.setAnnotation("comment", cn.getItem().getDescription());
7313 29 Aug 23 nicklas 273             
7313 29 Aug 23 nicklas 274             // Load some images
7313 29 Aug 23 nicklas 275             cn.setAnnotation("sunrisePlot", JsonUtil.loadLinkedItem(dc, cn.getItem(), "sunrise.png", Item.FILE, null));
7313 29 Aug 23 nicklas 276             cn.setAnnotation("segmentationPlot", JsonUtil.loadLinkedItem(dc, cn.getItem(), "ASPCF.png", Item.FILE, null));
7313 29 Aug 23 nicklas 277             cn.setAnnotation("ascatPlot", JsonUtil.loadLinkedItem(dc, cn.getItem(), "ASCATprofile.png", Item.FILE, null));
7341 11 Sep 23 nicklas 278             cn.setAnnotation("imbalanceTest", JsonUtil.loadLinkedItem(dc, cn.getItem(), "imbalance.test.txt", Item.FILE, null));
7405 08 Nov 23 nicklas 279             cn.setAnnotation("stats", JsonUtil.loadLinkedItem(dc, cn.getItem(), "stats.txt", Item.FILE, null));
7341 11 Sep 23 nicklas 280             
7341 11 Sep 23 nicklas 281             // More tumor and normal information
7341 11 Sep 23 nicklas 282             tumor.loadAnnotations(dc, manager, "ALIGNED_PAIRS", Annotationtype.ALIGNED_PAIRS, null);
7341 11 Sep 23 nicklas 283             tumor.loadAnnotations(dc, manager, "FRACTION_DUPLICATION", Annotationtype.FRACTION_DUPLICATION, null);
7341 11 Sep 23 nicklas 284             tumor.loadAnnotations(dc, manager, "MEAN_COVERAGE", Annotationtype.MEAN_COVERAGE, null);
7341 11 Sep 23 nicklas 285             tumor.loadAnnotations(dc, manager, "SD_COVERAGE", Annotationtype.SD_COVERAGE, null);
7341 11 Sep 23 nicklas 286             tumor.loadAnnotations(dc, manager, "FRACTION_OPTICAL_DUPLICATION", Annotationtype.FRACTION_OPTICAL_DUPLICATION, null);
7341 11 Sep 23 nicklas 287
7341 11 Sep 23 nicklas 288             AlignedSequences normal = cn.getNormalAlignment(dc);
7341 11 Sep 23 nicklas 289             normal.loadAnnotations(dc, manager, "ALIGNED_PAIRS", Annotationtype.ALIGNED_PAIRS, null);
7341 11 Sep 23 nicklas 290             normal.loadAnnotations(dc, manager, "FRACTION_DUPLICATION", Annotationtype.FRACTION_DUPLICATION, null);
7341 11 Sep 23 nicklas 291             normal.loadAnnotations(dc, manager, "MEAN_COVERAGE", Annotationtype.MEAN_COVERAGE, null);
7341 11 Sep 23 nicklas 292             normal.loadAnnotations(dc, manager, "SD_COVERAGE", Annotationtype.SD_COVERAGE, null);
7341 11 Sep 23 nicklas 293             normal.loadAnnotations(dc, manager, "FRACTION_OPTICAL_DUPLICATION", Annotationtype.FRACTION_OPTICAL_DUPLICATION, null);
7341 11 Sep 23 nicklas 294             cn.setAnnotation("normal", normal.asJSONObject());
7313 29 Aug 23 nicklas 295           }
7289 18 Aug 23 nicklas 296                     
7290 18 Aug 23 nicklas 297           jsonAscat.add(cn.asJSONObject());
7289 18 Aug 23 nicklas 298         }
7289 18 Aug 23 nicklas 299         
7290 18 Aug 23 nicklas 300         json.put("ascatItems", jsonAscat);
7290 18 Aug 23 nicklas 301       }
7290 18 Aug 23 nicklas 302     }
7267 21 Jun 23 nicklas 303     catch (Throwable t)
7267 21 Jun 23 nicklas 304     {
7267 21 Jun 23 nicklas 305       t.printStackTrace();
7267 21 Jun 23 nicklas 306       json.clear();
7267 21 Jun 23 nicklas 307       json.put("status", "error");
7267 21 Jun 23 nicklas 308       json.put("message", t.getMessage());
7267 21 Jun 23 nicklas 309       json.put("stacktrace", ThrowableUtil.stackTraceToString(t));
7267 21 Jun 23 nicklas 310     }
7267 21 Jun 23 nicklas 311     finally
7267 21 Jun 23 nicklas 312     {
7267 21 Jun 23 nicklas 313       if (dc != null) dc.close();
7267 21 Jun 23 nicklas 314       json.writeJSONString(resp.getWriter());
7267 21 Jun 23 nicklas 315     }
7267 21 Jun 23 nicklas 316     
7267 21 Jun 23 nicklas 317   }
7267 21 Jun 23 nicklas 318
7267 21 Jun 23 nicklas 319   @Override
7267 21 Jun 23 nicklas 320   protected void doPost(HttpServletRequest req, HttpServletResponse resp)
7267 21 Jun 23 nicklas 321     throws ServletException, IOException 
7267 21 Jun 23 nicklas 322   {
7267 21 Jun 23 nicklas 323     String cmd = req.getParameter("cmd");
7267 21 Jun 23 nicklas 324     JsonUtil.setJsonResponseHeaders(resp);
7267 21 Jun 23 nicklas 325     
7267 21 Jun 23 nicklas 326     JSONObject json = new JSONObject();
7267 21 Jun 23 nicklas 327     json.put("status", "ok");
7267 21 Jun 23 nicklas 328     JSONArray jsonMessages = new JSONArray();
7267 21 Jun 23 nicklas 329   
7267 21 Jun 23 nicklas 330     final SessionControl sc = Reggie.getSessionControl(req);
7267 21 Jun 23 nicklas 331     DbControl dc = null;
7267 21 Jun 23 nicklas 332     try
7267 21 Jun 23 nicklas 333     {
7267 21 Jun 23 nicklas 334
7267 21 Jun 23 nicklas 335       if ("StartAscatAnalysis".equals(cmd))
7267 21 Jun 23 nicklas 336       {
7267 21 Jun 23 nicklas 337         dc = sc.newDbControl(":Start ASCAT analysis");
7267 21 Jun 23 nicklas 338
7267 21 Jun 23 nicklas 339         ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.SECONDARY_ANALYSIS, ReggieRole.ADMINISTRATOR);
7267 21 Jun 23 nicklas 340
7267 21 Jun 23 nicklas 341         JSONObject jsonReq = JsonUtil.parseRequest(req);
7267 21 Jun 23 nicklas 342         JSONArray jsonAligned = (JSONArray)jsonReq.get("alignedSequences");
7267 21 Jun 23 nicklas 343       
7267 21 Jun 23 nicklas 344         Number ascatSoftwareId = (Number)jsonReq.get("ascatSoftware");
7267 21 Jun 23 nicklas 345       
7267 21 Jun 23 nicklas 346         String clusterId = (String)jsonReq.get("cluster");
7267 21 Jun 23 nicklas 347         boolean debug = Boolean.TRUE.equals(jsonReq.get("debug"));
7290 18 Aug 23 nicklas 348         // Auto-confirm is not supported since results need to be manually inspected
7290 18 Aug 23 nicklas 349         // boolean autoConfirm = Boolean.TRUE.equals(jsonReq.get("autoConfirm"));
7267 21 Jun 23 nicklas 350         Number priority = (Number)jsonReq.get("priority");
7267 21 Jun 23 nicklas 351         String partition = Values.getStringOrNull((String)jsonReq.get("partition"));
7372 06 Oct 23 nicklas 352         String submitOptions = Values.getStringOrNull((String)jsonReq.get("submitOptionsOverride"));
7279 11 Aug 23 nicklas 353         
7341 11 Sep 23 nicklas 354         AllelicImbalanceTest imbalanceTest = AllelicImbalanceTest.fromTitle((String)jsonReq.get("imbalanceTest"));
7279 11 Aug 23 nicklas 355         Number tau = (Number)jsonReq.get("tau");
7279 11 Aug 23 nicklas 356         Number rho = (Number)jsonReq.get("rho");
7279 11 Aug 23 nicklas 357         Number psi = (Number)jsonReq.get("psi");
7341 11 Sep 23 nicklas 358         Number penalty = (Number)jsonReq.get("penalty");
7341 11 Sep 23 nicklas 359         Number minDepth = (Number)jsonReq.get("minDepth");
7267 21 Jun 23 nicklas 360
7267 21 Jun 23 nicklas 361         OpenGridCluster cluster = OpenGridService.getInstance().getClusterById(dc, clusterId);
7267 21 Jun 23 nicklas 362         if (cluster == null)
7267 21 Jun 23 nicklas 363         {
7267 21 Jun 23 nicklas 364           throw new ItemNotFoundException("OpenGridCluster[" + clusterId + "]");
7267 21 Jun 23 nicklas 365         }
7267 21 Jun 23 nicklas 366
7267 21 Jun 23 nicklas 367         // Load common items
7267 21 Jun 23 nicklas 368         Software ascatSoftware = ascatSoftwareId != null ? Software.getById(dc, ascatSoftwareId.intValue()) : null;
7267 21 Jun 23 nicklas 369
7341 11 Sep 23 nicklas 370         // Configure delay between ASCAT jobs
7341 11 Sep 23 nicklas 371         BatchConfig batch = new BatchConfig();
7341 11 Sep 23 nicklas 372         batch.setDelayInterval(180); // 3 minutes delay
7341 11 Sep 23 nicklas 373         long initialDelay = NEXT_START_TIME-System.currentTimeMillis();
7341 11 Sep 23 nicklas 374         if (initialDelay > 0)
7341 11 Sep 23 nicklas 375         {
7341 11 Sep 23 nicklas 376           // We have to wait a bit also for the first job
7341 11 Sep 23 nicklas 377           batch.setInitialDelay((int)initialDelay/1000);
7341 11 Sep 23 nicklas 378         }
7341 11 Sep 23 nicklas 379         batch.lock();
7341 11 Sep 23 nicklas 380
7267 21 Jun 23 nicklas 381         AscatJobCreator jobCreator = new AscatJobCreator();
7341 11 Sep 23 nicklas 382         jobCreator.setBatchConfig(batch);
7267 21 Jun 23 nicklas 383         jobCreator.setDebug(debug);
7290 18 Aug 23 nicklas 384         // jobCreator.setAutoConfirm(autoConfirm);
7267 21 Jun 23 nicklas 385         jobCreator.setPriority(priority == null ? null : priority.intValue());
7267 21 Jun 23 nicklas 386         jobCreator.setPartition(partition);
7372 06 Oct 23 nicklas 387         jobCreator.setSubmitOptionsOverride(submitOptions);
7267 21 Jun 23 nicklas 388         jobCreator.setSoftware(ascatSoftware);
7341 11 Sep 23 nicklas 389         jobCreator.setAllelicImbalanceTest(imbalanceTest);
7279 11 Aug 23 nicklas 390         if (tau != null) jobCreator.setTau(tau.floatValue());
7279 11 Aug 23 nicklas 391         if (rho != null) jobCreator.setRho(rho.floatValue());
7279 11 Aug 23 nicklas 392         if (psi != null) jobCreator.setPsi(psi.floatValue());
7341 11 Sep 23 nicklas 393         if (penalty != null) jobCreator.setPenalty(penalty.intValue());
7341 11 Sep 23 nicklas 394         if (minDepth != null) jobCreator.setMinDepth(minDepth.intValue());
7268 22 Jun 23 nicklas 395         List<TumorNormalPair> pairs = new ArrayList<TumorNormalPair>();
7267 21 Jun 23 nicklas 396         for (int alNo = 0; alNo < jsonAligned.size(); alNo++)
7267 21 Jun 23 nicklas 397         {
7267 21 Jun 23 nicklas 398           JSONObject jsonAl = (JSONObject)jsonAligned.get(alNo);
7268 22 Jun 23 nicklas 399           Number tumorId = (Number)jsonAl.get("tumorId");
7268 22 Jun 23 nicklas 400           Number normalId = (Number)jsonAl.get("normalId");
7267 21 Jun 23 nicklas 401         
7268 22 Jun 23 nicklas 402           TumorNormalPair pair = new TumorNormalPair(
7268 22 Jun 23 nicklas 403             AlignedSequences.getById(dc, tumorId.intValue()), 
7268 22 Jun 23 nicklas 404             AlignedSequences.getById(dc, normalId.intValue()));
7268 22 Jun 23 nicklas 405           pairs.add(pair);
7267 21 Jun 23 nicklas 406
7267 21 Jun 23 nicklas 407           // Reset AUTO_PROCESSING annotation
7268 22 Jun 23 nicklas 408           Annotationtype.AUTO_PROCESSING.setAnnotationValue(dc, pair.tumor.getDerivedBioAssay(), null);
7267 21 Jun 23 nicklas 409         }
7267 21 Jun 23 nicklas 410
7268 22 Jun 23 nicklas 411         List<JobDefinition> jobDefs = jobCreator.createAscatJobs(dc, cluster, pairs);
7267 21 Jun 23 nicklas 412         List<Job> jobs = ScriptUtil.submitJobs(dc, cluster, jobDefs);
7341 11 Sep 23 nicklas 413         // Remember this time so that a new batch is also delayed
7341 11 Sep 23 nicklas 414         NEXT_START_TIME = batch.getNextStartTime();
7267 21 Jun 23 nicklas 415         for (Job job : jobs)
7267 21 Jun 23 nicklas 416         {
7267 21 Jun 23 nicklas 417           if (job.getStatus() == Job.Status.ERROR)
7267 21 Jun 23 nicklas 418           {
7267 21 Jun 23 nicklas 419             jsonMessages.add("[Error]Job submission for '" + job.getName() + "' failed: " + job.getStatusMessage());
7267 21 Jun 23 nicklas 420           }
7267 21 Jun 23 nicklas 421           else
7267 21 Jun 23 nicklas 422           {
7267 21 Jun 23 nicklas 423             jsonMessages.add("Submitted ASCAT analysis job to " + cluster.getConnectionInfo().getName() + " with id " + job.getExternalId());
7267 21 Jun 23 nicklas 424           }
7267 21 Jun 23 nicklas 425         }
7267 21 Jun 23 nicklas 426         dc.commit();
7267 21 Jun 23 nicklas 427       }
7293 22 Aug 23 nicklas 428       else if ("RegisterAscatResults".equals(cmd))
7293 22 Aug 23 nicklas 429       {
7293 22 Aug 23 nicklas 430         dc = sc.newDbControl(":Confirm ASCAT analysis");
7267 21 Jun 23 nicklas 431
7293 22 Aug 23 nicklas 432         ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.SECONDARY_ANALYSIS, ReggieRole.ADMINISTRATOR);
7293 22 Aug 23 nicklas 433
7293 22 Aug 23 nicklas 434         JSONObject jsonReq = JsonUtil.parseRequest(req);
7293 22 Aug 23 nicklas 435         JSONArray jsonAscatItems = (JSONArray)jsonReq.get("ascatItems");
7293 22 Aug 23 nicklas 436
7293 22 Aug 23 nicklas 437         int numAccepted = 0;
7293 22 Aug 23 nicklas 438         int numNotAccepted = 0;
7293 22 Aug 23 nicklas 439         int numUndecided = 0;
7293 22 Aug 23 nicklas 440         int numReAnalyze = 0;
7293 22 Aug 23 nicklas 441         int numDeleted = 0;
7293 22 Aug 23 nicklas 442         
7293 22 Aug 23 nicklas 443         ItemList ascatPipeline = BiomaterialList.ASCAT_PIPELINE.load(dc);
7293 22 Aug 23 nicklas 444         List<BasicItem> toDelete = new ArrayList<BasicItem>();
7293 22 Aug 23 nicklas 445         
7293 22 Aug 23 nicklas 446         for (int ascatNo = 0; ascatNo < jsonAscatItems.size(); ++ascatNo)
7293 22 Aug 23 nicklas 447         {
7293 22 Aug 23 nicklas 448           JSONObject jsonAscat = (JSONObject)jsonAscatItems.get(ascatNo);
7293 22 Aug 23 nicklas 449           Number ascatId = (Number)jsonAscat.get("id");
7293 22 Aug 23 nicklas 450           boolean reAnalyze = Boolean.TRUE.equals(jsonAscat.get("reAnalyze"));
7293 22 Aug 23 nicklas 451           boolean delete = Boolean.TRUE.equals(jsonAscat.get("delete"));
7293 22 Aug 23 nicklas 452           
7293 22 Aug 23 nicklas 453           CopyNumber cn = CopyNumber.getById(dc, ascatId.intValue());
7293 22 Aug 23 nicklas 454           DerivedBioAssay ascat = cn.getItem();
7293 22 Aug 23 nicklas 455           if (reAnalyze)
7293 22 Aug 23 nicklas 456           {
7293 22 Aug 23 nicklas 457             AlignedSequences tumor = cn.getTumorAlignment(dc);
7293 22 Aug 23 nicklas 458             Annotationtype.AUTO_PROCESSING.setAnnotationValue(dc, tumor.getItem(), "ReProcess");
7293 22 Aug 23 nicklas 459             ascatPipeline.add(tumor.getDerivedBioAssay());
7293 22 Aug 23 nicklas 460             numReAnalyze++;
7293 22 Aug 23 nicklas 461           }
7293 22 Aug 23 nicklas 462           if (delete)
7293 22 Aug 23 nicklas 463           {
7293 22 Aug 23 nicklas 464             ascat.setRemoved(true);
7293 22 Aug 23 nicklas 465             toDelete.add(ascat);
7293 22 Aug 23 nicklas 466             toDelete.addAll(Reggie.removeAttachedFiles(dc, ascat));
7293 22 Aug 23 nicklas 467             numDeleted++;
7293 22 Aug 23 nicklas 468           }
7293 22 Aug 23 nicklas 469           else
7293 22 Aug 23 nicklas 470           {
7293 22 Aug 23 nicklas 471             Annotationtype.AUTO_PROCESSING.setAnnotationValue(dc, ascat, null);          
7293 22 Aug 23 nicklas 472             String comment = Values.getStringOrNull((String)jsonAscat.get("comment"));
7293 22 Aug 23 nicklas 473             ascat.setDescription(comment);
7293 22 Aug 23 nicklas 474             
7293 22 Aug 23 nicklas 475             Job job = ascat.getJob();
7293 22 Aug 23 nicklas 476             if (job.getStatus() == Job.Status.ERROR)
7293 22 Aug 23 nicklas 477             {
7293 22 Aug 23 nicklas 478               Annotationtype.ANALYSIS_RESULT.setAnnotationValue(dc, ascat, "Failed");
7293 22 Aug 23 nicklas 479               Annotationtype.ASCAT_RESULT.setAnnotationValue(dc, ascat, "Failed");
7293 22 Aug 23 nicklas 480             }
7293 22 Aug 23 nicklas 481             else
7293 22 Aug 23 nicklas 482             {
7293 22 Aug 23 nicklas 483               String ascatResult = (String)jsonAscat.get("ascatResult");
7293 22 Aug 23 nicklas 484               if ("Undecided".equals(ascatResult))
7293 22 Aug 23 nicklas 485               {
7293 22 Aug 23 nicklas 486                 numUndecided++;
7293 22 Aug 23 nicklas 487               }
7293 22 Aug 23 nicklas 488               else
7293 22 Aug 23 nicklas 489               {
7293 22 Aug 23 nicklas 490                 Annotationtype.ANALYSIS_RESULT.setAnnotationValue(dc, ascat, "Successful");
7293 22 Aug 23 nicklas 491                 if ("Accepted".equals(ascatResult))
7293 22 Aug 23 nicklas 492                 {
7293 22 Aug 23 nicklas 493                   numAccepted++;
7293 22 Aug 23 nicklas 494                 }
7293 22 Aug 23 nicklas 495                 else if ("NotAccepted".equals(ascatResult))
7293 22 Aug 23 nicklas 496                 {
7293 22 Aug 23 nicklas 497                   numNotAccepted++;
7293 22 Aug 23 nicklas 498                 }
7293 22 Aug 23 nicklas 499               }
7293 22 Aug 23 nicklas 500               Annotationtype.ASCAT_RESULT.setAnnotationValue(dc, ascat, ascatResult);
7293 22 Aug 23 nicklas 501             }
7293 22 Aug 23 nicklas 502           }
7293 22 Aug 23 nicklas 503         }
7293 22 Aug 23 nicklas 504         
7293 22 Aug 23 nicklas 505         if (numAccepted > 0)
7293 22 Aug 23 nicklas 506         {
7293 22 Aug 23 nicklas 507           jsonMessages.add("Results accepted for " + numAccepted + " ASCAT items");
7293 22 Aug 23 nicklas 508           ActivityDef.ASCAT_ACCEPTED.merge(dc, numAccepted);
7293 22 Aug 23 nicklas 509         }
7293 22 Aug 23 nicklas 510         if (numNotAccepted > 0)
7293 22 Aug 23 nicklas 511         {
7293 22 Aug 23 nicklas 512           jsonMessages.add("Results not accepted for " + numNotAccepted + " ASCAT items");
7293 22 Aug 23 nicklas 513         }
7293 22 Aug 23 nicklas 514         if (numReAnalyze > 0)
7293 22 Aug 23 nicklas 515         {
7293 22 Aug 23 nicklas 516           jsonMessages.add(numReAnalyze + " items flagged for new ASCAT analysis");
7293 22 Aug 23 nicklas 517         }
7293 22 Aug 23 nicklas 518         if (numDeleted > 0)
7293 22 Aug 23 nicklas 519         {
7293 22 Aug 23 nicklas 520           jsonMessages.add(numDeleted + " results deleted");
7293 22 Aug 23 nicklas 521         }
7293 22 Aug 23 nicklas 522         if (numUndecided > 0)
7293 22 Aug 23 nicklas 523         {
7293 22 Aug 23 nicklas 524           jsonMessages.add(numUndecided + " results remain undecided");
7293 22 Aug 23 nicklas 525         }
7293 22 Aug 23 nicklas 526         dc.commit();
7293 22 Aug 23 nicklas 527         if (toDelete.size() > 0)
7293 22 Aug 23 nicklas 528         {
7293 22 Aug 23 nicklas 529           try
7293 22 Aug 23 nicklas 530           {
7293 22 Aug 23 nicklas 531             Trashcan.delete(sc, toDelete, false, null);
7293 22 Aug 23 nicklas 532           }
7293 22 Aug 23 nicklas 533           catch (RuntimeException ex)
7293 22 Aug 23 nicklas 534           {
7293 22 Aug 23 nicklas 535             ex.printStackTrace();
7293 22 Aug 23 nicklas 536             jsonMessages.add("[Error]Could not delete all items created by failed jobs: " + ex.getMessage());
7293 22 Aug 23 nicklas 537           }
7293 22 Aug 23 nicklas 538         }
7293 22 Aug 23 nicklas 539       }
7267 21 Jun 23 nicklas 540       json.put("messages", jsonMessages);
7267 21 Jun 23 nicklas 541       CounterService.getInstance().setForceCount();
7267 21 Jun 23 nicklas 542     }
7267 21 Jun 23 nicklas 543     catch (Throwable t)
7267 21 Jun 23 nicklas 544     {
7267 21 Jun 23 nicklas 545       t.printStackTrace();
7267 21 Jun 23 nicklas 546       json.clear();
7267 21 Jun 23 nicklas 547       json.put("status", "error");
7267 21 Jun 23 nicklas 548       json.put("message", t.getMessage());
7267 21 Jun 23 nicklas 549       json.put("stacktrace", ThrowableUtil.stackTraceToString(t));
7267 21 Jun 23 nicklas 550     }
7267 21 Jun 23 nicklas 551     finally
7267 21 Jun 23 nicklas 552     {
7267 21 Jun 23 nicklas 553       if (dc != null) dc.close();
7267 21 Jun 23 nicklas 554       json.writeJSONString(resp.getWriter());
7267 21 Jun 23 nicklas 555     }
7267 21 Jun 23 nicklas 556     
7267 21 Jun 23 nicklas 557   }
7267 21 Jun 23 nicklas 558   
7267 21 Jun 23 nicklas 559   
7267 21 Jun 23 nicklas 560
7267 21 Jun 23 nicklas 561 }