extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/plugins/GeneReportsCombinerPlugin.java

Code
Comments
Other
Rev Date Author Line
2911 10 Nov 14 nicklas 1 package net.sf.basedb.reggie.plugins;
2911 10 Nov 14 nicklas 2
3503 22 Sep 15 nicklas 3 import java.io.ByteArrayInputStream;
3503 22 Sep 15 nicklas 4 import java.io.ByteArrayOutputStream;
2911 10 Nov 14 nicklas 5 import java.io.IOException;
2911 10 Nov 14 nicklas 6 import java.io.InputStream;
2911 10 Nov 14 nicklas 7 import java.util.ArrayList;
2911 10 Nov 14 nicklas 8 import java.util.Arrays;
3788 17 Mar 16 nicklas 9 import java.util.Collection;
2911 10 Nov 14 nicklas 10 import java.util.Collections;
2911 10 Nov 14 nicklas 11 import java.util.List;
2911 10 Nov 14 nicklas 12 import java.util.Set;
2911 10 Nov 14 nicklas 13
2911 10 Nov 14 nicklas 14 import net.sf.basedb.core.AnyToAny;
2911 10 Nov 14 nicklas 15 import net.sf.basedb.core.BaseException;
3499 21 Sep 15 nicklas 16 import net.sf.basedb.core.BooleanParameterType;
2911 10 Nov 14 nicklas 17 import net.sf.basedb.core.DbControl;
2911 10 Nov 14 nicklas 18 import net.sf.basedb.core.File;
2911 10 Nov 14 nicklas 19 import net.sf.basedb.core.Item;
2911 10 Nov 14 nicklas 20 import net.sf.basedb.core.ItemContext;
2911 10 Nov 14 nicklas 21 import net.sf.basedb.core.ItemNotFoundException;
2911 10 Nov 14 nicklas 22 import net.sf.basedb.core.ItemParameterType;
2911 10 Nov 14 nicklas 23 import net.sf.basedb.core.ItemQuery;
2911 10 Nov 14 nicklas 24 import net.sf.basedb.core.PluginParameter;
2911 10 Nov 14 nicklas 25 import net.sf.basedb.core.ProgressReporter;
2911 10 Nov 14 nicklas 26 import net.sf.basedb.core.RawBioAssay;
2911 10 Nov 14 nicklas 27 import net.sf.basedb.core.RequestInformation;
6033 29 Oct 20 nicklas 28 import net.sf.basedb.core.Sample;
3503 22 Sep 15 nicklas 29 import net.sf.basedb.core.SystemItems;
2911 10 Nov 14 nicklas 30 import net.sf.basedb.core.Type;
2911 10 Nov 14 nicklas 31 import net.sf.basedb.core.Job.ExecutionTime;
6033 29 Oct 20 nicklas 32 import net.sf.basedb.core.Path;
2911 10 Nov 14 nicklas 33 import net.sf.basedb.core.StringParameterType;
3503 22 Sep 15 nicklas 34 import net.sf.basedb.core.User;
2911 10 Nov 14 nicklas 35 import net.sf.basedb.core.plugin.AbstractExporterPlugin;
2911 10 Nov 14 nicklas 36 import net.sf.basedb.core.plugin.ExportOutputStream;
2911 10 Nov 14 nicklas 37 import net.sf.basedb.core.plugin.GuiContext;
2911 10 Nov 14 nicklas 38 import net.sf.basedb.core.plugin.InteractivePlugin;
2911 10 Nov 14 nicklas 39 import net.sf.basedb.core.plugin.Request;
2911 10 Nov 14 nicklas 40 import net.sf.basedb.core.plugin.Response;
2911 10 Nov 14 nicklas 41 import net.sf.basedb.core.query.Expressions;
2911 10 Nov 14 nicklas 42 import net.sf.basedb.core.query.Hql;
2911 10 Nov 14 nicklas 43 import net.sf.basedb.core.query.Restrictions;
2911 10 Nov 14 nicklas 44 import net.sf.basedb.reggie.dao.Rawbioassay;
4665 31 Jan 18 nicklas 45 import net.sf.basedb.reggie.dao.Rawdatatype;
3503 22 Sep 15 nicklas 46 import net.sf.basedb.reggie.dao.ReggieRole;
6033 29 Oct 20 nicklas 47 import net.sf.basedb.reggie.dao.Subtype;
3506 23 Sep 15 nicklas 48 import net.sf.basedb.reggie.pdf.PdfReportWorker;
3788 17 Mar 16 nicklas 49 import net.sf.basedb.reggie.pdf.PdfToPdfCombiner;
3788 17 Mar 16 nicklas 50 import net.sf.basedb.reggie.pdf.PdfToZipCombiner;
3788 17 Mar 16 nicklas 51 import net.sf.basedb.reggie.pdf.PdfCombiner;
3506 23 Sep 15 nicklas 52 import net.sf.basedb.reggie.pdf.PdfReportTemplate;
6060 17 Nov 20 nicklas 53 import net.sf.basedb.reggie.pdf.PdfUtil7;
2911 10 Nov 14 nicklas 54 import net.sf.basedb.util.Enumeration;
3498 18 Sep 15 nicklas 55 import net.sf.basedb.util.FileUtil;
2911 10 Nov 14 nicklas 56 import net.sf.basedb.util.NameableComparator;
2911 10 Nov 14 nicklas 57
2911 10 Nov 14 nicklas 58 public class GeneReportsCombinerPlugin 
2911 10 Nov 14 nicklas 59   extends AbstractExporterPlugin 
2911 10 Nov 14 nicklas 60   implements InteractivePlugin  
2911 10 Nov 14 nicklas 61 {
2911 10 Nov 14 nicklas 62
3566 29 Oct 15 nicklas 63   private String encryptionPassword;
3563 28 Oct 15 nicklas 64   
2911 10 Nov 14 nicklas 65   public GeneReportsCombinerPlugin()
2911 10 Nov 14 nicklas 66   {}
2911 10 Nov 14 nicklas 67   
2911 10 Nov 14 nicklas 68   /*
2911 10 Nov 14 nicklas 69      From the Plugin interface
2911 10 Nov 14 nicklas 70      --------------------------------
2911 10 Nov 14 nicklas 71   */
2911 10 Nov 14 nicklas 72   @Override
2911 10 Nov 14 nicklas 73   public boolean supportsConfigurations()
2911 10 Nov 14 nicklas 74   {
3499 21 Sep 15 nicklas 75     return true;
2911 10 Nov 14 nicklas 76   }
2911 10 Nov 14 nicklas 77   @Override
2911 10 Nov 14 nicklas 78   public boolean requiresConfiguration()
2911 10 Nov 14 nicklas 79   {
3500 21 Sep 15 nicklas 80     return true;
2911 10 Nov 14 nicklas 81   }
2911 10 Nov 14 nicklas 82
2911 10 Nov 14 nicklas 83   // -------------------------------------
2911 10 Nov 14 nicklas 84   /*
2911 10 Nov 14 nicklas 85      From the InteractivePlugin interface
2911 10 Nov 14 nicklas 86      -------------------------------------------
2911 10 Nov 14 nicklas 87   */
2911 10 Nov 14 nicklas 88   /**
2911 10 Nov 14 nicklas 89     The plug-in will appear on list page for raw bioassays.
2911 10 Nov 14 nicklas 90   */
2911 10 Nov 14 nicklas 91   @Override
2911 10 Nov 14 nicklas 92   public Set<GuiContext> getGuiContexts()
2911 10 Nov 14 nicklas 93   {
2911 10 Nov 14 nicklas 94     return Collections.singleton(GuiContext.list(Item.RAWBIOASSAY));
2911 10 Nov 14 nicklas 95   }
2911 10 Nov 14 nicklas 96   @Override
2911 10 Nov 14 nicklas 97   public String isInContext(GuiContext context, Object item)
2911 10 Nov 14 nicklas 98   {
2911 10 Nov 14 nicklas 99     return null;
2911 10 Nov 14 nicklas 100   }
2911 10 Nov 14 nicklas 101   @Override
2911 10 Nov 14 nicklas 102   public RequestInformation getRequestInformation(GuiContext context, String command) 
2911 10 Nov 14 nicklas 103     throws BaseException
2911 10 Nov 14 nicklas 104   {
2911 10 Nov 14 nicklas 105     RequestInformation requestInformation = null;
3499 21 Sep 15 nicklas 106     if (Request.COMMAND_CONFIGURE_PLUGIN.equals(command))
2911 10 Nov 14 nicklas 107     {
3499 21 Sep 15 nicklas 108       requestInformation = getConfigurePluginParameters();
3499 21 Sep 15 nicklas 109     }
3499 21 Sep 15 nicklas 110     else if (Request.COMMAND_CONFIGURE_JOB.equals(command))
3499 21 Sep 15 nicklas 111     {
2911 10 Nov 14 nicklas 112       requestInformation = getConfigureJobParameters(context, null);
2911 10 Nov 14 nicklas 113     }
2911 10 Nov 14 nicklas 114     return requestInformation;
2911 10 Nov 14 nicklas 115   }
2911 10 Nov 14 nicklas 116   
2911 10 Nov 14 nicklas 117   @SuppressWarnings("unchecked")
2911 10 Nov 14 nicklas 118   @Override
2911 10 Nov 14 nicklas 119   public void configure(GuiContext context, Request request, Response response)
2911 10 Nov 14 nicklas 120   {
2911 10 Nov 14 nicklas 121     String command = request.getCommand();
2911 10 Nov 14 nicklas 122     DbControl dc = null;
2911 10 Nov 14 nicklas 123     try
2911 10 Nov 14 nicklas 124     {
3500 21 Sep 15 nicklas 125       if (command.equals(Request.COMMAND_CONFIGURE_PLUGIN))
2911 10 Nov 14 nicklas 126       {
3500 21 Sep 15 nicklas 127         RequestInformation ri = getConfigurePluginParameters();
3500 21 Sep 15 nicklas 128         List<Throwable> errors = validateRequestParameters(ri.getParameters(), request);
3500 21 Sep 15 nicklas 129         if (errors != null)
3500 21 Sep 15 nicklas 130         {
3500 21 Sep 15 nicklas 131           response.setError(errors.size() + " invalid parameters were found in the request",errors);
3500 21 Sep 15 nicklas 132           return;
3500 21 Sep 15 nicklas 133         }
3500 21 Sep 15 nicklas 134         storeValue(configuration, request, ri.getParameter("report"));
3500 21 Sep 15 nicklas 135         response.setDone("Configuration complete");
3500 21 Sep 15 nicklas 136       }
3500 21 Sep 15 nicklas 137       else if (command.equals(Request.COMMAND_CONFIGURE_JOB))
3500 21 Sep 15 nicklas 138       {
2911 10 Nov 14 nicklas 139         RequestInformation ri = getConfigureJobParameters(context, !request.isAllowedImmediateExecution());
2911 10 Nov 14 nicklas 140         List<Throwable> errors = validateRequestParameters(ri.getParameters(), request);
2911 10 Nov 14 nicklas 141         if (errors != null)
2911 10 Nov 14 nicklas 142         {
2911 10 Nov 14 nicklas 143           response.setError(errors.size() + " invalid parameters were found in the request",errors);
2911 10 Nov 14 nicklas 144           return;
2911 10 Nov 14 nicklas 145         }
2911 10 Nov 14 nicklas 146   
2911 10 Nov 14 nicklas 147         if (!request.isAllowedImmediateExecution())
2911 10 Nov 14 nicklas 148         {
2911 10 Nov 14 nicklas 149           response.setError("Immediate download must be enabled for this plug-in.", null);
2911 10 Nov 14 nicklas 150           return;
2911 10 Nov 14 nicklas 151         }
2911 10 Nov 14 nicklas 152
2911 10 Nov 14 nicklas 153         storeValue(job, request, ri.getParameter("whichItems"));
2911 10 Nov 14 nicklas 154         storeValue(job, request, ri.getParameter("filename"));
3498 18 Sep 15 nicklas 155         storeValue(job, request, ri.getParameter("format"));
3503 22 Sep 15 nicklas 156         storeValue(job, request, ri.getParameter("addPersonalInformation"));
3563 28 Oct 15 nicklas 157         // Only store password in memory and not as a job parameter
3563 28 Oct 15 nicklas 158         // This works because we require immediate execution 
3563 28 Oct 15 nicklas 159         // (otherwise a new instance is created and the password is lost)
3566 29 Oct 15 nicklas 160         encryptionPassword = (String)request.getParameterValue("encryptionPassword");
2911 10 Nov 14 nicklas 161
2911 10 Nov 14 nicklas 162         String whichItems = (String)request.getParameterValue("whichItems");
2911 10 Nov 14 nicklas 163         ItemContext cc = sc.getCurrentContext(context.getItem(), context.getSubContext());
5673 15 Oct 19 nicklas 164         PdfReportTemplate reportType = PdfReportTemplate.getByCName((String)getJobOrConfigurationValue("report"), null);
5673 15 Oct 19 nicklas 165         Rawdatatype requiredRawDataType = reportType.getRawDataType();
2911 10 Nov 14 nicklas 166         ItemQuery<RawBioAssay> query = (ItemQuery<RawBioAssay>)cc.getQuery();
5673 15 Oct 19 nicklas 167         if (requiredRawDataType != null) 
5673 15 Oct 19 nicklas 168         {
5673 15 Oct 19 nicklas 169           requiredRawDataType.addFilter(dc, query);
5673 15 Oct 19 nicklas 170         }
2911 10 Nov 14 nicklas 171         if ("all".equals(whichItems))
2911 10 Nov 14 nicklas 172         {  
2911 10 Nov 14 nicklas 173           query.setFirstResult(0);
2911 10 Nov 14 nicklas 174           query.setMaxResults(0);
2911 10 Nov 14 nicklas 175         }
2911 10 Nov 14 nicklas 176         else if ("selected".equals(whichItems))
2911 10 Nov 14 nicklas 177         {
2911 10 Nov 14 nicklas 178           query.setFirstResult(0);
2911 10 Nov 14 nicklas 179           query.setMaxResults(0);
2911 10 Nov 14 nicklas 180           query.restrict(
2911 10 Nov 14 nicklas 181             Restrictions.in(
2911 10 Nov 14 nicklas 182               Hql.property("id"),
2911 10 Nov 14 nicklas 183               Expressions.parameter("_selected_", cc.getSelected(), Type.INT)
2911 10 Nov 14 nicklas 184             )
2911 10 Nov 14 nicklas 185           );
2911 10 Nov 14 nicklas 186         }
2911 10 Nov 14 nicklas 187           
2911 10 Nov 14 nicklas 188         dc = sc.newDbControl();
2911 10 Nov 14 nicklas 189         List<RawBioAssay> rawBioAssays = query.list(dc);
2911 10 Nov 14 nicklas 190         if (rawBioAssays.size() == 0)
2911 10 Nov 14 nicklas 191         {
5673 15 Oct 19 nicklas 192           if (requiredRawDataType != null)
5673 15 Oct 19 nicklas 193           {
5673 15 Oct 19 nicklas 194             response.setError("None of the specified raw bioassays have " + requiredRawDataType.getName() + " data", null);
5673 15 Oct 19 nicklas 195           }
5673 15 Oct 19 nicklas 196           else
5673 15 Oct 19 nicklas 197           {
5673 15 Oct 19 nicklas 198             response.setError("No raw bioassays have been selected", null);
5673 15 Oct 19 nicklas 199           }
2911 10 Nov 14 nicklas 200           return;
2911 10 Nov 14 nicklas 201         }
2911 10 Nov 14 nicklas 202         else
2911 10 Nov 14 nicklas 203         {
2911 10 Nov 14 nicklas 204           job.setValues("rawBioAssays", new ItemParameterType<RawBioAssay>(RawBioAssay.class, null, true, 0, null), rawBioAssays);
2911 10 Nov 14 nicklas 205           
5673 15 Oct 19 nicklas 206           response.setSuggestedJobName("Combine \"" + reportType.getReportName() + "\" for " + rawBioAssays.size() + " raw bioassays");
2911 10 Nov 14 nicklas 207           response.setDownloadImmediately("The job configuration is complete", ExecutionTime.SHORTEST, true);
2911 10 Nov 14 nicklas 208         }
2911 10 Nov 14 nicklas 209       }
2911 10 Nov 14 nicklas 210     }
2911 10 Nov 14 nicklas 211     catch(Throwable ex)
2911 10 Nov 14 nicklas 212     {
2911 10 Nov 14 nicklas 213       response.setError(ex.getMessage(), Arrays.asList(ex));
2911 10 Nov 14 nicklas 214     }
2911 10 Nov 14 nicklas 215     finally
2911 10 Nov 14 nicklas 216     {
2911 10 Nov 14 nicklas 217       if (dc != null) dc.close();
2911 10 Nov 14 nicklas 218     }
2911 10 Nov 14 nicklas 219   }
2911 10 Nov 14 nicklas 220   // ------------------------------------------------
2911 10 Nov 14 nicklas 221
3499 21 Sep 15 nicklas 222   private RequestInformation getConfigurePluginParameters()
3499 21 Sep 15 nicklas 223   {
3499 21 Sep 15 nicklas 224     List<PluginParameter<?>> parameters = new ArrayList<PluginParameter<?>>();
3499 21 Sep 15 nicklas 225     
3500 21 Sep 15 nicklas 226     Enumeration<String, String> reportOptions = new Enumeration<String, String>();
3500 21 Sep 15 nicklas 227     reportOptions.add("GENE_REPORT", "Gene report");
3500 21 Sep 15 nicklas 228     reportOptions.add("PILOT_REPORT", "Pilot report");
5737 20 Nov 19 nicklas 229 //    reportOptions.add("SCANB_REPORT", "SCAN-B report");
3500 21 Sep 15 nicklas 230     parameters.add(new PluginParameter<String>
3500 21 Sep 15 nicklas 231     (
3500 21 Sep 15 nicklas 232       "report", "Report", "Select the report to combine by this configuration", null,
3500 21 Sep 15 nicklas 233       new StringParameterType(255, null, true, 1, 0, 0, reportOptions)
3499 21 Sep 15 nicklas 234     ));
3499 21 Sep 15 nicklas 235     
3500 21 Sep 15 nicklas 236     RequestInformation configurePlugin = new RequestInformation
3500 21 Sep 15 nicklas 237     (
3500 21 Sep 15 nicklas 238       Request.COMMAND_CONFIGURE_PLUGIN, 
3500 21 Sep 15 nicklas 239       "Combine reports options", 
3500 21 Sep 15 nicklas 240       "Set options for the combined report.", 
3500 21 Sep 15 nicklas 241       parameters
3500 21 Sep 15 nicklas 242     );
3500 21 Sep 15 nicklas 243     return configurePlugin;
3500 21 Sep 15 nicklas 244
3499 21 Sep 15 nicklas 245   }
2911 10 Nov 14 nicklas 246
3499 21 Sep 15 nicklas 247
2911 10 Nov 14 nicklas 248   private RequestInformation getConfigureJobParameters(GuiContext context, Boolean requireFile)
2911 10 Nov 14 nicklas 249   {
3500 21 Sep 15 nicklas 250     String reportType = (String)getJobOrConfigurationValue("report");
3506 23 Sep 15 nicklas 251     PdfReportTemplate report = PdfReportTemplate.getByCName(reportType, PdfReportTemplate.GENE_REPORT);
3500 21 Sep 15 nicklas 252
2911 10 Nov 14 nicklas 253     RequestInformation configureJob = null;
2961 19 Nov 14 nicklas 254     DbControl dc = null;
2961 19 Nov 14 nicklas 255     try
2911 10 Nov 14 nicklas 256     {
2961 19 Nov 14 nicklas 257       dc = sc.newDbControl();    
2961 19 Nov 14 nicklas 258       List<PluginParameter<?>> parameters = new ArrayList<PluginParameter<?>>();
2961 19 Nov 14 nicklas 259       ItemContext cc = sc.getCurrentContext(context.getItem(), context.getSubContext());
2911 10 Nov 14 nicklas 260       
2961 19 Nov 14 nicklas 261       String defaultWhich = "all";
2961 19 Nov 14 nicklas 262       Enumeration<String, String> options = new Enumeration<String, String>();
2961 19 Nov 14 nicklas 263       if (cc.getSelected().size() > 0)
2961 19 Nov 14 nicklas 264       {
2961 19 Nov 14 nicklas 265         options.add("selected", "Selected items");
2961 19 Nov 14 nicklas 266         defaultWhich = "selected";
2961 19 Nov 14 nicklas 267       }
2961 19 Nov 14 nicklas 268       options.add("all", "All items");
2961 19 Nov 14 nicklas 269         
2961 19 Nov 14 nicklas 270       parameters.add(new PluginParameter<String>
2911 10 Nov 14 nicklas 271         (
3498 18 Sep 15 nicklas 272           "whichItems", "Which raw bioassays", "The raw bioassays to create a combined report for.", defaultWhich,
2961 19 Nov 14 nicklas 273           new StringParameterType(255, defaultWhich, true, 1, 0, 0, options)
2911 10 Nov 14 nicklas 274         ));
2961 19 Nov 14 nicklas 275       parameters.add(new PluginParameter<String>
2961 19 Nov 14 nicklas 276         (
3500 21 Sep 15 nicklas 277           "filename", "Report filename", "The filename to look for when searching for existing reports.", report.getDefaultFilename(),
3500 21 Sep 15 nicklas 278           new StringParameterType(255, report.getDefaultFilename(), true)
2961 19 Nov 14 nicklas 279         ));
2961 19 Nov 14 nicklas 280       
3503 22 Sep 15 nicklas 281       
3563 28 Oct 15 nicklas 282       String defaultCombine = "ZIP";
3498 18 Sep 15 nicklas 283       Enumeration<String, String> combineOptions = new Enumeration<String, String>();
3498 18 Sep 15 nicklas 284       combineOptions.add("PDF", "PDF");
3498 18 Sep 15 nicklas 285       combineOptions.add("ZIP", "ZIP");
3566 29 Oct 15 nicklas 286       combineOptions.add("ZIP*", "ZIP*");
3498 18 Sep 15 nicklas 287       parameters.add(new PluginParameter<String>
3498 18 Sep 15 nicklas 288       (
3503 22 Sep 15 nicklas 289         "format", "Output format", "Select the output format for the combined reports\n\n"
3498 18 Sep 15 nicklas 290             + "PDF = Creates a single PDF with one page for each report\n"
3566 29 Oct 15 nicklas 291             + "ZIP = Creates a ZIP file with one file for each report\n"
3566 29 Oct 15 nicklas 292             + "ZIP* = Creates a ZIP file with one encrypted file for each report (the ZIP itself is not encrypted)", 
3566 29 Oct 15 nicklas 293             defaultCombine,
3498 18 Sep 15 nicklas 294         new StringParameterType(255, defaultCombine, true, 1, 0, 0, combineOptions)
3499 21 Sep 15 nicklas 295       ));
3498 18 Sep 15 nicklas 296       
3566 29 Oct 15 nicklas 297       parameters.add(new PluginParameter<String>("encryptionPassword", "Encryption password", 
3566 29 Oct 15 nicklas 298         "Specify a password to create a password-protected and encrypted ZIP/PDF file. " +
3566 29 Oct 15 nicklas 299         "The password is required for extracting files from the ZIP file or viewing the PDF file. " +
3566 29 Oct 15 nicklas 300         "The encryption is done with 256-bit AES (Advanced Encryption Standard).", 
3563 28 Oct 15 nicklas 301         new StringParameterType()));
3563 28 Oct 15 nicklas 302       
3503 22 Sep 15 nicklas 303       if (report.supportsPersonalInformation())
3503 22 Sep 15 nicklas 304       {
3503 22 Sep 15 nicklas 305         boolean isPatientCurator = ReggieRole.PATIENT_CURATOR.isMember(dc);
3503 22 Sep 15 nicklas 306         boolean isAdmin =  ReggieRole.ADMINISTRATOR.isMember(dc);
3503 22 Sep 15 nicklas 307         boolean isRoot = sc.getLoggedInUserId() == SystemItems.getId(User.ROOT);
3503 22 Sep 15 nicklas 308         
3503 22 Sep 15 nicklas 309         if (isPatientCurator || isAdmin || isRoot)
3503 22 Sep 15 nicklas 310         {
3503 22 Sep 15 nicklas 311           parameters.add(new PluginParameter<Boolean>
3503 22 Sep 15 nicklas 312             (
3503 22 Sep 15 nicklas 313               "addPersonalInformation", "Add personal information", 
3503 22 Sep 15 nicklas 314               "Select this option to add personal information about the patients in the combined PDF.", 
3503 22 Sep 15 nicklas 315               new BooleanParameterType(true, false)
3503 22 Sep 15 nicklas 316             ));
3503 22 Sep 15 nicklas 317         }
3503 22 Sep 15 nicklas 318       }
3503 22 Sep 15 nicklas 319
3503 22 Sep 15 nicklas 320       
2961 19 Nov 14 nicklas 321       configureJob = new RequestInformation
2961 19 Nov 14 nicklas 322       (
2961 19 Nov 14 nicklas 323         Request.COMMAND_CONFIGURE_JOB, 
3498 18 Sep 15 nicklas 324         "Report options", 
3506 23 Sep 15 nicklas 325         "Set options for combining the \"" + report.getReportName() + "\" PDF:s", 
2961 19 Nov 14 nicklas 326         parameters
2961 19 Nov 14 nicklas 327       );
2911 10 Nov 14 nicklas 328     }
2961 19 Nov 14 nicklas 329     finally
2961 19 Nov 14 nicklas 330     {
2961 19 Nov 14 nicklas 331       if (dc != null) dc.close();
2961 19 Nov 14 nicklas 332     }
2911 10 Nov 14 nicklas 333       
2911 10 Nov 14 nicklas 334     return configureJob;
2911 10 Nov 14 nicklas 335   }
2911 10 Nov 14 nicklas 336
2911 10 Nov 14 nicklas 337   /*
2911 10 Nov 14 nicklas 338     From the AbstractExporterPlugin interface
2911 10 Nov 14 nicklas 339     -----------------------------------------
2911 10 Nov 14 nicklas 340   */
2911 10 Nov 14 nicklas 341   private DbControl dc;
2911 10 Nov 14 nicklas 342   private int combined;
2911 10 Nov 14 nicklas 343   private int skipped;
2911 10 Nov 14 nicklas 344   
2911 10 Nov 14 nicklas 345   
2911 10 Nov 14 nicklas 346   @Override
2911 10 Nov 14 nicklas 347   protected void begin(DbControl dc)
2911 10 Nov 14 nicklas 348   {
2911 10 Nov 14 nicklas 349     this.dc = dc;
2911 10 Nov 14 nicklas 350     this.combined = 0;
2911 10 Nov 14 nicklas 351     this.skipped = 0;
2911 10 Nov 14 nicklas 352   }
2911 10 Nov 14 nicklas 353   
2911 10 Nov 14 nicklas 354   @Override
2911 10 Nov 14 nicklas 355   protected void performExport(ExportOutputStream out, ProgressReporter progress)
2911 10 Nov 14 nicklas 356     throws IOException
2911 10 Nov 14 nicklas 357   {
3498 18 Sep 15 nicklas 358     PdfCombiner combiner = null;
2911 10 Nov 14 nicklas 359     try
2911 10 Nov 14 nicklas 360     {
3788 17 Mar 16 nicklas 361       // Select PDF combiner from the "format" parameter
3788 17 Mar 16 nicklas 362       String format = (String)job.getValue("format");
3788 17 Mar 16 nicklas 363       boolean encryptBeforeCombine = false;
3498 18 Sep 15 nicklas 364       if ("ZIP".equals(format))
3498 18 Sep 15 nicklas 365       {
3566 29 Oct 15 nicklas 366         // Encrypt the ZIP archive
3788 17 Mar 16 nicklas 367         //combiner = new PdfToZipCombiner(filename, out, encryptionPassword);
3788 17 Mar 16 nicklas 368         combiner = new PdfToZipCombiner(out, encryptionPassword);
3498 18 Sep 15 nicklas 369       }
3566 29 Oct 15 nicklas 370       else if ("ZIP*".equals(format))
3566 29 Oct 15 nicklas 371       {
3566 29 Oct 15 nicklas 372         // Encrypt the PDF:s but not the ZIP archive
3566 29 Oct 15 nicklas 373         encryptBeforeCombine = true;
3788 17 Mar 16 nicklas 374         combiner = new PdfToZipCombiner(out, null);
3566 29 Oct 15 nicklas 375       }
3498 18 Sep 15 nicklas 376       else
3498 18 Sep 15 nicklas 377       {
6060 17 Nov 20 nicklas 378         PdfUtil7 pdfOut = new PdfUtil7("Combined report", null);
3788 17 Mar 16 nicklas 379         pdfOut.open(out, encryptionPassword);
3788 17 Mar 16 nicklas 380         combiner = new PdfToPdfCombiner(pdfOut);
3498 18 Sep 15 nicklas 381       }
2911 10 Nov 14 nicklas 382       
3788 17 Mar 16 nicklas 383       // Get the report template
3788 17 Mar 16 nicklas 384       String reportType = (String)getJobOrConfigurationValue("report");
3788 17 Mar 16 nicklas 385       PdfReportTemplate report = PdfReportTemplate.getByCName(reportType, PdfReportTemplate.GENE_REPORT);
3788 17 Mar 16 nicklas 386       String filename = (String)job.getValue("filename");
3788 17 Mar 16 nicklas 387       if (filename == null) filename = report.getDefaultFilename();
3788 17 Mar 16 nicklas 388   
3788 17 Mar 16 nicklas 389       // Send MIME type and suggested filename
3788 17 Mar 16 nicklas 390       out.setMimeType(combiner.getMimeType());
3788 17 Mar 16 nicklas 391       out.setFilename(combiner.getOutFilename(filename));
3788 17 Mar 16 nicklas 392       
5363 16 Apr 19 nicklas 393       List<RawBioAssay> rawBioAssays = job.getValues("rawBioAssays");
3788 17 Mar 16 nicklas 394       Collections.sort(rawBioAssays, new NameableComparator<RawBioAssay>(false));
3788 17 Mar 16 nicklas 395       
3788 17 Mar 16 nicklas 396       boolean includePersonalInformation = report.supportsPersonalInformation() && 
3788 17 Mar 16 nicklas 397         Boolean.TRUE.equals(job.getValue("addPersonalInformation"));
3788 17 Mar 16 nicklas 398   
3788 17 Mar 16 nicklas 399       PdfReportCombiner reporter = new PdfReportCombiner(report, combiner);
3788 17 Mar 16 nicklas 400       reporter.setIncludePersonalInformation(includePersonalInformation);
3788 17 Mar 16 nicklas 401       if (encryptBeforeCombine) reporter.setEnryptionPassword(encryptionPassword);
3788 17 Mar 16 nicklas 402   
3788 17 Mar 16 nicklas 403       combined = reporter.combineReports(dc, rawBioAssays, filename, progress);
3788 17 Mar 16 nicklas 404       skipped = rawBioAssays.size() - combined;
3788 17 Mar 16 nicklas 405     }
3788 17 Mar 16 nicklas 406     catch (IOException ex)
3788 17 Mar 16 nicklas 407     {
3788 17 Mar 16 nicklas 408       ex.printStackTrace(System.out);
3788 17 Mar 16 nicklas 409       throw ex;
3788 17 Mar 16 nicklas 410     }
3788 17 Mar 16 nicklas 411     catch (RuntimeException ex)
3788 17 Mar 16 nicklas 412     {
3788 17 Mar 16 nicklas 413       ex.printStackTrace(System.out);
3788 17 Mar 16 nicklas 414       throw ex;
3788 17 Mar 16 nicklas 415     }
3788 17 Mar 16 nicklas 416     finally
3788 17 Mar 16 nicklas 417     {
3788 17 Mar 16 nicklas 418       FileUtil.close(combiner);
3788 17 Mar 16 nicklas 419       out.flush();
3788 17 Mar 16 nicklas 420     }
3788 17 Mar 16 nicklas 421   }
3788 17 Mar 16 nicklas 422   
3788 17 Mar 16 nicklas 423   @Override
3788 17 Mar 16 nicklas 424   protected void end(boolean success)
3788 17 Mar 16 nicklas 425   {
3788 17 Mar 16 nicklas 426     this.dc = null;
3788 17 Mar 16 nicklas 427   }
3788 17 Mar 16 nicklas 428   
3788 17 Mar 16 nicklas 429   @Override
3788 17 Mar 16 nicklas 430   protected String getSuccessMessage()
3788 17 Mar 16 nicklas 431   {
3788 17 Mar 16 nicklas 432     String msg = "Combined reports for " + combined + " raw bioassays.";
3788 17 Mar 16 nicklas 433     if (skipped > 0) msg += " Skipped " + skipped + " that was not found.";
3788 17 Mar 16 nicklas 434     return msg;
3788 17 Mar 16 nicklas 435   }
3788 17 Mar 16 nicklas 436
3788 17 Mar 16 nicklas 437   /**
3788 17 Mar 16 nicklas 438     Helper class for combining multiple PDF reports into a single
3788 17 Mar 16 nicklas 439     entity (eg. a single PDF, ZIP file, etc.). A report template
3788 17 Mar 16 nicklas 440     and a combiner is required. Additional options may be set to
3788 17 Mar 16 nicklas 441     include personal information, enable encryption, etc.
3788 17 Mar 16 nicklas 442     
3788 17 Mar 16 nicklas 443     @since 4.3
3788 17 Mar 16 nicklas 444   */
3788 17 Mar 16 nicklas 445   public static class PdfReportCombiner 
3788 17 Mar 16 nicklas 446   {
3788 17 Mar 16 nicklas 447   
3788 17 Mar 16 nicklas 448     private final PdfReportTemplate report;
3788 17 Mar 16 nicklas 449     private final PdfCombiner combiner;
3788 17 Mar 16 nicklas 450     
3788 17 Mar 16 nicklas 451     private boolean includePersonalInformation;
3788 17 Mar 16 nicklas 452     private String encryptionPassword;
3788 17 Mar 16 nicklas 453     
3788 17 Mar 16 nicklas 454     /**
3788 17 Mar 16 nicklas 455       Create a new combiner instance.
3788 17 Mar 16 nicklas 456       @param report The type of report to combine
3788 17 Mar 16 nicklas 457       @param combiner The combiner instance that creates the final output
3788 17 Mar 16 nicklas 458     */
3788 17 Mar 16 nicklas 459     public PdfReportCombiner(PdfReportTemplate report, PdfCombiner combiner)
3788 17 Mar 16 nicklas 460     {
3788 17 Mar 16 nicklas 461       this.report = report;
3788 17 Mar 16 nicklas 462       this.combiner = combiner;
3788 17 Mar 16 nicklas 463     }
3788 17 Mar 16 nicklas 464     
3788 17 Mar 16 nicklas 465     /**
3788 17 Mar 16 nicklas 466       Set this flag to include overlay personal information
3788 17 Mar 16 nicklas 467       on the reports before they are combined.
3788 17 Mar 16 nicklas 468     */
3788 17 Mar 16 nicklas 469     public void setIncludePersonalInformation(boolean include)
3788 17 Mar 16 nicklas 470     {
3788 17 Mar 16 nicklas 471       this.includePersonalInformation = include;
3788 17 Mar 16 nicklas 472     }
3788 17 Mar 16 nicklas 473     
3788 17 Mar 16 nicklas 474     /**
3788 17 Mar 16 nicklas 475       Set an encryption password that is used to encrypt
3788 17 Mar 16 nicklas 476       the individual PDF:s before the are combined. Note 
3788 17 Mar 16 nicklas 477       that some combiners do not support this feature.
3788 17 Mar 16 nicklas 478     */
3788 17 Mar 16 nicklas 479     public void setEnryptionPassword(String password)
3788 17 Mar 16 nicklas 480     {
3788 17 Mar 16 nicklas 481       this.encryptionPassword = combiner.supportsEncryptBeforeCombine() ? password : null;
3788 17 Mar 16 nicklas 482     }
3788 17 Mar 16 nicklas 483     
3788 17 Mar 16 nicklas 484     /**
3788 17 Mar 16 nicklas 485       Combine the PDF reports that are found as any-to-any links on the
3788 17 Mar 16 nicklas 486       given raw bioassays. If a filename not given the default
3788 17 Mar 16 nicklas 487       filename for the report type is used (PdfReportTemplate.getDefaultFilename()).
3788 17 Mar 16 nicklas 488        
3788 17 Mar 16 nicklas 489     */
3788 17 Mar 16 nicklas 490     public int combineReports(DbControl dc, Collection<RawBioAssay> items, String filename, ProgressReporter progress)
3788 17 Mar 16 nicklas 491       throws IOException
3788 17 Mar 16 nicklas 492     {
3788 17 Mar 16 nicklas 493       if (filename == null) filename = report.getDefaultFilename();
3788 17 Mar 16 nicklas 494       PdfReportWorker worker = report.getWorker(null);
3788 17 Mar 16 nicklas 495       
3788 17 Mar 16 nicklas 496       int total = items.size();
2911 10 Nov 14 nicklas 497       int current = 0;
3788 17 Mar 16 nicklas 498       int combined = 0;
3788 17 Mar 16 nicklas 499       int skipped = 0;
3788 17 Mar 16 nicklas 500       
3788 17 Mar 16 nicklas 501       for (RawBioAssay rba : items)
2911 10 Nov 14 nicklas 502       {
2911 10 Nov 14 nicklas 503         Rawbioassay raw = Rawbioassay.getById(dc, rba.getId());
2911 10 Nov 14 nicklas 504         rba = raw.getItem();
2911 10 Nov 14 nicklas 505   
2911 10 Nov 14 nicklas 506         if (progress != null)
2911 10 Nov 14 nicklas 507         {
3788 17 Mar 16 nicklas 508           progress.display((100 * current) / total, "Including " + filename + " for " + raw.getName() + "...");
2911 10 Nov 14 nicklas 509         }
2911 10 Nov 14 nicklas 510         current++;
2911 10 Nov 14 nicklas 511         
2911 10 Nov 14 nicklas 512         // Get existing PDF
2911 10 Nov 14 nicklas 513         InputStream existingPdf = null;
3498 18 Sep 15 nicklas 514         File file = null;
2911 10 Nov 14 nicklas 515         try
2911 10 Nov 14 nicklas 516         {
2911 10 Nov 14 nicklas 517           AnyToAny link = AnyToAny.getByName(dc, rba, filename);
2911 10 Nov 14 nicklas 518           if (link.getToType() == Item.FILE)
2911 10 Nov 14 nicklas 519           {
3498 18 Sep 15 nicklas 520             file = (File)link.getTo();
3498 18 Sep 15 nicklas 521             existingPdf = file.getDownloadStream(0);
3788 17 Mar 16 nicklas 522             if (includePersonalInformation || encryptionPassword != null)
3503 22 Sep 15 nicklas 523             {
3503 22 Sep 15 nicklas 524               // We need to create a temporary PDF and overlay the personal information on it
6092 14 Dec 20 nicklas 525               PdfUtil7 pdf = new PdfUtil7(existingPdf);
6092 14 Dec 20 nicklas 526               if (includePersonalInformation)
6092 14 Dec 20 nicklas 527               {
6092 14 Dec 20 nicklas 528                 // Apply redaction to existing PDF
6092 14 Dec 20 nicklas 529                 byte[] redactedPdf = worker.redactBeforePersonalInformation(dc, raw, pdf);
6092 14 Dec 20 nicklas 530                 if (redactedPdf != null)
6092 14 Dec 20 nicklas 531                 {
6092 14 Dec 20 nicklas 532                   pdf = new PdfUtil7(new ByteArrayInputStream(redactedPdf));
6092 14 Dec 20 nicklas 533                 }
6092 14 Dec 20 nicklas 534               }
6092 14 Dec 20 nicklas 535               
3503 22 Sep 15 nicklas 536               ByteArrayOutputStream personalPdf = new ByteArrayOutputStream((int)file.getSize());
3788 17 Mar 16 nicklas 537               pdf.open(personalPdf, encryptionPassword);
3566 29 Oct 15 nicklas 538               if (includePersonalInformation)
3566 29 Oct 15 nicklas 539               {
3566 29 Oct 15 nicklas 540                 worker.addPersonalInformation(dc, raw, pdf);
3566 29 Oct 15 nicklas 541               }
3503 22 Sep 15 nicklas 542               pdf.close();
3503 22 Sep 15 nicklas 543               
3503 22 Sep 15 nicklas 544               // Now, we pass on the modified PDF to the PdfCombiner object
3503 22 Sep 15 nicklas 545               existingPdf = new ByteArrayInputStream(personalPdf.toByteArray());
3503 22 Sep 15 nicklas 546             }
2911 10 Nov 14 nicklas 547           }
2911 10 Nov 14 nicklas 548         }
2911 10 Nov 14 nicklas 549         catch (ItemNotFoundException ex)
2911 10 Nov 14 nicklas 550         {}
2911 10 Nov 14 nicklas 551         
3498 18 Sep 15 nicklas 552         try
2911 10 Nov 14 nicklas 553         {
6033 29 Oct 20 nicklas 554           String pdfFilename = Path.makeSafeFilename(raw.getName(), "")+".pdf";
6092 14 Dec 20 nicklas 555           if (report.useExternalIds() && !includePersonalInformation)
3498 18 Sep 15 nicklas 556           {
6033 29 Oct 20 nicklas 557             Sample specimen = (Sample)raw.findSingleParent(dc, Subtype.SPECIMEN);
6068 19 Nov 20 nicklas 558             if (specimen != null && specimen.getExternalId() != null)
6033 29 Oct 20 nicklas 559             {
6033 29 Oct 20 nicklas 560               pdfFilename = pdfFilename.replace(specimen.getName(), specimen.getExternalId());
6033 29 Oct 20 nicklas 561             }
6033 29 Oct 20 nicklas 562           }
6033 29 Oct 20 nicklas 563           if (existingPdf != null && combiner.addFile(existingPdf, pdfFilename))
6033 29 Oct 20 nicklas 564           {
3498 18 Sep 15 nicklas 565             combined++;
3498 18 Sep 15 nicklas 566           }
3498 18 Sep 15 nicklas 567           else
3498 18 Sep 15 nicklas 568           {
3498 18 Sep 15 nicklas 569             skipped++;
3498 18 Sep 15 nicklas 570           }
2911 10 Nov 14 nicklas 571         }
3498 18 Sep 15 nicklas 572         catch (IOException ex)
2911 10 Nov 14 nicklas 573         {
3498 18 Sep 15 nicklas 574           ex.printStackTrace(System.out);
3498 18 Sep 15 nicklas 575           skipped++;
2911 10 Nov 14 nicklas 576         }
2911 10 Nov 14 nicklas 577       }
2911 10 Nov 14 nicklas 578       
2911 10 Nov 14 nicklas 579       if (progress != null)
2911 10 Nov 14 nicklas 580       {
3506 23 Sep 15 nicklas 581         String msg = "Combined \""+report.getReportName() + "\" for " + combined + " raw bioassays.";
2911 10 Nov 14 nicklas 582         if (skipped > 0) msg += " Skipped " + skipped + " that was not found.";
2911 10 Nov 14 nicklas 583         progress.display(100, msg);
2911 10 Nov 14 nicklas 584       }
3503 22 Sep 15 nicklas 585       
3788 17 Mar 16 nicklas 586       return combined;
3503 22 Sep 15 nicklas 587     }
3498 18 Sep 15 nicklas 588     
3788 17 Mar 16 nicklas 589    
3498 18 Sep 15 nicklas 590   }
2911 10 Nov 14 nicklas 591 }