/* * Copyright (C) 2011 SeqWare * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.sourceforge.seqware.pipeline.plugins; import io.seqware.common.model.WorkflowRunStatus; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import joptsimple.ArgumentAcceptingOptionSpec; import net.sourceforge.seqware.common.module.ReturnValue; import net.sourceforge.seqware.common.util.Log; import net.sourceforge.seqware.common.util.TabExpansionUtil; import net.sourceforge.seqware.pipeline.plugin.Plugin; import net.sourceforge.seqware.pipeline.plugin.PluginInterface; import org.openide.util.lookup.ServiceProvider; /** * <p> * WorkflowRunReporter class. * </p> * * @author mtaschuk, boconnor * @version $Id: $Id */ @ServiceProvider(service = PluginInterface.class) public class WorkflowRunReporter extends Plugin { private static final String WRSTDERR = "wr-stderr"; private static final String WRSTDOUT = "wr-stdout"; private ReturnValue ret = new ReturnValue(); private String csvFileName = null; private Writer writer; private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_kkmmss"); private static final int STDOUT = 1; private static final int STDERR = 2; private final ArgumentAcceptingOptionSpec<WorkflowRunStatus> statusSpec; /** * <p> * Constructor for WorkflowRunReporter. * </p> */ public WorkflowRunReporter() { super(); parser.acceptsAll(Arrays.asList("workflow-run-accession", "wra"), "The SWID of the workflow run").withRequiredArg(); parser.acceptsAll(Arrays.asList("workflow-accession", "wa"), "The SWID of " + "a workflow. All the workflow runs for that workflow will be " + "retrieved.").withRequiredArg(); parser.acceptsAll( Arrays.asList("time-period", "t"), "Dates to check for " + "workflow runs. Dates are in format YYYY-MM-DD. If one date is " + "provided, from that point to the present is checked. If two, " + "separated by hyphen YYYY-MM-DDL:YYYY-MM-DD then it checks " + "that range").withRequiredArg(); parser.acceptsAll(Arrays.asList("output-filename", "o"), "Optional: The output filename").withRequiredArg(); parser.acceptsAll(Arrays.asList("stdout"), "Prints to standard out instead of to a file"); parser.acceptsAll(Arrays.asList(WRSTDOUT), "Optional: will print the stdout of the workflow run, must specify the --workflow-run-accession"); parser.acceptsAll(Arrays.asList(WRSTDERR), "Optional: will print the stderr of the workflow run, must specify the --workflow-run-accession"); this.statusSpec = parser .accepts( "status", "Optional: Specify a particular status to restrict workflow runs that will be returned, status is one of " + Arrays.toString(WorkflowRunStatus.values())).withRequiredArg().ofType(WorkflowRunStatus.class); parser.acceptsAll(Arrays.asList("human"), "Optional: will print output in expanded human friendly format"); ret.setExitStatus(ReturnValue.SUCCESS); } /** * {@inheritDoc} * * @return */ @Override public ReturnValue init() { return ret; } /** * {@inheritDoc} * * @return */ @Override public ReturnValue do_test() { return ret; } /** * {@inheritDoc} * * @return */ @Override public ReturnValue do_run() { try { String timePeriod = null; WorkflowRunStatus status = options.valueOf(statusSpec); if (options.has("time-period")) { timePeriod = (String) options.valueOf("time-period"); } /* * FIXME: I think this is problematic since the DB may use GMT whereas the Date() command returns something localized (I think). * We need to standardize on date/time across out DB and Java code. */ Date firstDate = null, lastDate = null; if (timePeriod != null) { String[] dates = timePeriod.trim().split(":"); SimpleDateFormat localDateFormat = new SimpleDateFormat("yyyy-MM-dd"); try { firstDate = localDateFormat.parse(dates[0].trim()); if (dates.length != 1) { lastDate = localDateFormat.parse(dates[1].trim()); } } catch (ParseException ex) { Log.warn("Date not found. Date must be in format YYYY-MM-DD or YYYY-MM-DD:YYYY-MM-DD.", ex); println("Incorrect date"); ret = new ReturnValue(ReturnValue.INVALIDPARAMETERS); return ret; } if (lastDate == null) { lastDate = new Date(); } } if (options.has(WRSTDERR) && options.has(WRSTDOUT)) { println("Combination of both stdout and stderr not recognized"); ret.setExitStatus(ReturnValue.INVALIDPARAMETERS); return ret; } if (options.has("workflow-run-accession")) { String wra = (String) options.valueOf("workflow-run-accession"); if (options.has(WRSTDERR)) { reportWorkflowRunStdErrOut(wra, STDERR); } else if (options.has(WRSTDOUT)) { reportWorkflowRunStdErrOut(wra, STDOUT); } else { reportOnWorkflowRun(wra); } } else if (options.has("workflow-accession") || options.has(statusSpec)) { String tp = (String) options.valueOf("workflow-accession"); reportOnWorkflow(tp, status, firstDate, lastDate); } /** * SEQWARE-863 ability to query without specifying a specific workflow-accession was removed else if (firstDate != null || * lastDate != null) { reportOnWorkflowRuns(firstDate, lastDate); */ else { println("Combination of parameters not recognized!"); println(this.get_syntax()); ret.setExitStatus(ReturnValue.INVALIDPARAMETERS); return ret; } } catch (IOException e) { Log.error(e.getMessage(), e); ret.setExitStatus(ReturnValue.FILENOTREADABLE); ret.setDescription(e.getMessage()); } return ret; } private void reportOnWorkflowRun(String workflowRunAccession) throws IOException { String title = "workflowrun_" + workflowRunAccession; initWriter(title); String report; try { report = metadata.getWorkflowRunReport(Integer.parseInt(workflowRunAccession)); } catch (RuntimeException e) { println("Workflow run not found"); ret = new ReturnValue(ReturnValue.INVALIDPARAMETERS); return; } if (options.has("human")) { writer.write(TabExpansionUtil.expansion(report)); return; } writer.write(report); } private void reportWorkflowRunStdErrOut(String workflowRunAccession, int streamType) throws IOException { String title = "workflowrun_" + workflowRunAccession; if (streamType == 1) { title = title + "_STDOUT"; initWriter(title); writer.write(metadata.getWorkflowRunReportStdOut(Integer.parseInt(workflowRunAccession))); } else if (streamType == 2) { title = title + "_STDERR"; initWriter(title); writer.write(metadata.getWorkflowRunReportStdErr(Integer.parseInt(workflowRunAccession))); } else { Log.error("Unknown stream type: " + streamType + " should be " + WorkflowRunReporter.STDERR + " for stderr or " + WorkflowRunReporter.STDOUT + " for stdout!"); initWriter(title); writer.write("Unknown stream type: " + streamType + " should be " + WorkflowRunReporter.STDERR + " for stderr or " + WorkflowRunReporter.STDOUT + " for stdout!"); } } private void reportOnWorkflow(String workflowAccession, WorkflowRunStatus status, Date earlyDate, Date lateDate) throws IOException { String title = ""; if (workflowAccession != null) { title = "workflow_" + workflowAccession; } if (status != null) { title += "status_" + status.name(); } if (earlyDate != null) { title += "from" + dateFormat.format(earlyDate); } if (lateDate != null) { title += "to" + dateFormat.format(lateDate); } initWriter(title); String report; try { Integer workflowParameter = null; if (workflowAccession != null) { workflowParameter = Integer.parseInt(workflowAccession); } report = metadata.getWorkflowRunReport(workflowParameter, status, earlyDate, lateDate); } catch (RuntimeException e) { Log.fatal("Workflow not found", e); ret = new ReturnValue(ReturnValue.INVALIDPARAMETERS); return; } if (options.has("human")) { writer.write(TabExpansionUtil.expansion(report)); return; } writer.write(report); } private void initWriter(String string) throws IOException { String filename = dateFormat.format(new Date()) + "__" + string + ".csv"; if (options.has("output-filename") && options.valueOf("output-filename") != null && !"".equals(options.valueOf("output-filename"))) { filename = (String) options.valueOf("output-filename"); } csvFileName = filename; if (options.has("stdout")) { writer = new StringWriter(); } else { writer = new BufferedWriter(new FileWriter(csvFileName, true)); } } /** * {@inheritDoc} * * @return */ @Override public ReturnValue clean_up() { try { writer.flush(); writer.close(); if (options.has("stdout")) { Log.stdout(writer.toString()); } } catch (IOException ex) { Log.error("Writer is already closed.", ex); } return ret; } /** * {@inheritDoc} * * @return */ @Override public String get_description() { return "This plugin creates a tab-separated file that describes one or more " + "workflow runs, including the identity, library samples and " + "input and output files. " + "For more information, see " + "see http://seqware.github.com/docs/19-workflow-run-reporter/"; } }