/*
* 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.ProcessingStatus;
import io.seqware.common.model.SequencerRunStatus;
import io.seqware.common.model.WorkflowRunStatus;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import joptsimple.ArgumentAcceptingOptionSpec;
import net.sourceforge.seqware.common.model.ExperimentLibraryDesign;
import net.sourceforge.seqware.common.model.ExperimentSpotDesign;
import net.sourceforge.seqware.common.model.LibrarySelection;
import net.sourceforge.seqware.common.model.LibrarySource;
import net.sourceforge.seqware.common.model.LibraryStrategy;
import net.sourceforge.seqware.common.model.Organism;
import net.sourceforge.seqware.common.model.Platform;
import net.sourceforge.seqware.common.model.StudyType;
import net.sourceforge.seqware.common.model.WorkflowRun;
import net.sourceforge.seqware.common.module.FileMetadata;
import net.sourceforge.seqware.common.module.ReturnValue;
import net.sourceforge.seqware.common.util.Log;
import net.sourceforge.seqware.common.util.runtools.ConsoleAdapter;
import net.sourceforge.seqware.pipeline.plugin.Plugin;
import net.sourceforge.seqware.pipeline.plugin.PluginInterface;
import org.openide.util.lookup.ServiceProvider;
/**
* This plugin currently lets users creation a limited set of table rows in the database from the command line. In the future we should
* expand this tool to make it both more generic and to increase the number of tables that can be added to. Here's a list of TODO items we
* should add at some point: * TODO: ability to update rows in addition to creating and listing them * FIXME: better support for lookup
* tables rather than just hard-coding
*
* @author Brian O'Connor <briandoconnor@gmail.com>
* @version $Id: $Id
*/
@ServiceProvider(service = PluginInterface.class)
public class Metadata extends Plugin {
ReturnValue ret = new ReturnValue();
BufferedWriter bw = null;
/**
* Generic HashMap is extended here to not add keys when they are null.
*/
HashMap<String, String> fields = new HashMap<String, String>() {
@Override
public String put(String key, String value) {
if (value != null) {
return super.put(key, value);
} else {
return null;
}
}
};
protected boolean interactive = false;
// list of files
ArrayList<FileMetadata> files = new ArrayList<>();
private final ArgumentAcceptingOptionSpec<Integer> inputFileSpec;
/**
* <p>
* Constructor for Metadata.
* </p>
*/
public Metadata() {
super();
parser.acceptsAll(Arrays.asList("list-tables", "lt"),
"Optional: if provided will list out the tables this tools knows how to read and/or write to.");
parser.acceptsAll(Arrays.asList("table", "t"), "Required: the table you are interested in reading or writing.").withRequiredArg();
// parser.acceptsAll(Arrays.asList("list", "l"),
// "Optional: if provided will list out the table rows currently in the MetaDB your settings point to.");
parser.acceptsAll(
Arrays.asList("output-file", "of"),
"Optional: if provided along with the --list or --list-tables options this will cause the output list of rows/tables to be written to the file specified rather than stdout.")
.withRequiredArg();
parser.acceptsAll(Arrays.asList("list-fields", "lf"),
"Optional: if provided along with the --table option this will list out the fields for that table and their type.");
parser.acceptsAll(
Arrays.asList("field", "f"),
"Optional: the field you are interested in writing. This is encoded as '<field_name>::<value>', you should use single quotes when the value includes spaces. You supply multiple --field arguments for a given table insert.")
.withRequiredArg();
parser.acceptsAll(
Arrays.asList("file"),
"Optional: one file option can be specified when you create a file, one or more --file options can be specified when you create a workflow_run. This is encoded as '<algorithm>::<file-meta-type>::<file-path>', you should use single quotes when the value includes spaces.")
.withRequiredArg();
inputFileSpec = parser
.acceptsAll(Arrays.asList("input-file"),
"Optional: one or more --input-file options can be specified when you create a workflow_run. This is encoded as a SWID")
.withRequiredArg().ofType(Integer.class);
parser.acceptsAll(Arrays.asList("parent-accession"),
"Optional: one or more --parent-accession options can be specified when you create a workflow_run.").withRequiredArg();
parser.acceptsAll(Arrays.asList("create", "c"),
"Optional: indicates you want to create a new row, must supply --table and all the required --field params.");
parser.accepts("interactive", "Optional: Interactively prompt for fields during creation");
ret.setExitStatus(ReturnValue.SUCCESS);
}
/**
* {@inheritDoc}
*
* @return
*/
@Override
public ReturnValue init() {
interactive = options.has("interactive");
parseFiles();
return parseFields();
}
/**
* {@inheritDoc}
*
* @return
*/
@Override
public ReturnValue do_test() {
return ret;
}
/**
* {@inheritDoc}
*
* @return
*/
@Override
public ReturnValue do_run() {
// setup output file
if (options.has("output-file")) {
try {
bw = new BufferedWriter(new FileWriter(new File((String) options.valueOf("output-file"))));
} catch (IOException ex) {
bw = null;
Log.error(null, ex);
}
}
// parse any fields into hash
if (options.has("list-tables")) {
print("TableName\n");
for (String table : new String[] { "study", "experiment", "sample", "sequencer_run", "ius", "lane", "workflow", "workflow_run" }) {
print(table + "\n");
}
} else if (options.has("table") && options.has("list")) {
// list the table's contents
} else if (options.has("table") && options.has("list-fields")) {
// list the fields for this table
ret = (listFields((String) options.valueOf("table")));
return ret;
} else if (options.has("table") && options.has("create") && (options.has("field") || options.has("interactive"))) {
if (null != (String) options.valueOf("table")) // create a row with these fields
// create a row with these fields
switch ((String) options.valueOf("table")) {
case "study":
ret = addStudy();
return ret;
case "experiment":
ret = addExperiment();
return ret;
case "sample":
ret = addSample();
return ret;
case "sequencer_run":
ret = addSequencerRun();
return ret;
case "lane":
ret = addLane();
return ret;
case "ius":
ret = addIUS();
return ret;
case "workflow":
ret = addWorkflow();
return ret;
case "workflow_run":
ret = addWorkflowRun();
return ret;
case "file":
ret = addFile();
return ret;
default:
Log.error("This tool does not know how to save to the " + options.valueOf("table") + " table.");
break;
}
} else {
println("Combination of parameters not recognized!");
println(this.get_syntax());
ret.setExitStatus(ReturnValue.INVALIDPARAMETERS);
}
return ret;
}
/**
* list the fields available to set
*
* @param table
* @return
*/
protected ReturnValue listFields(String table) {
final String fileDescription = "\nThis takes one file encoded as --file type::file-meta-type::file-path[::description] \n";
ReturnValue rv = new ReturnValue(ReturnValue.SUCCESS);
if (null != table)
switch (table) {
case "study":
List<StudyType> studyTypes = this.metadata.getStudyTypes();
print("Field\tType\tPossible_Values\ntitle\tString\ndescription\tString\ncenter_name\tString\ncenter_project_name\tString\nstudy_type\tInteger\t[");
for (StudyType st : studyTypes) {
print(st.getStudyTypeId() + ": " + st.getName() + ", ");
} // "1: Whole Genome Sequencing, 2: Metagenomics, 3: Transcriptome Analysis, 4: Resequencing, 5: Epigenetics, 6: Synthetic Genomics, 7: Forensic or Paleo-genomics, 8: Gene Regulation Study, 9: Cancer Genomics, 10: Population Genomics, 11: Other"
print("]\n");
break;
case "experiment": {
print("Field\tType\tPossible_Values\ntitle\tString\ndescription\tString\nstudy_accession\tInteger\nplatform_id\tInteger\t[");
List<Platform> platforms = this.metadata.getPlatforms();
for (Platform obj : platforms) {
print(obj.getPlatformId() + ": " + obj.getName() + " " + obj.getInstrumentModel() + ", ");
}
print("]\n");
print("experiment_library_design_id\tInteger\t[");
List<ExperimentLibraryDesign> elds = this.metadata.getExperimentLibraryDesigns();
for (ExperimentLibraryDesign obj : elds) {
print(obj.getExperimentLibraryDesignId() + ": " + obj.getName() + ", ");
}
print("]\n");
print("experiment_spot_design_id\tInteger\t[");
List<ExperimentSpotDesign> esds = this.metadata.getExperimentSpotDesigns();
for (ExperimentSpotDesign obj : esds) {
print(obj.getExperimentSpotDesignId() + ": " + obj.getReadSpec() + ", ");
}
print("]\n");
break;
}
case "sample": {
print("Field\tType\tPossible_Values\ntitle\tString\ndescription\tString\nexperiment_accession\tInteger\nparent_sample_accession\tInteger\norganism_id\tInteger\t[\n");
List<Organism> objs = this.metadata.getOrganisms();
for (Organism obj : objs) {
print(obj.getOrganismId() + ": " + obj.getName() + ", ");
}
print("]\n");
break;
}
case "sequencer_run": {
print("Field\tType\tPossible_Values\nname\tString\ndescription\tString\npaired_end\tBoolean\t[true, false]\nskip\tBoolean\t[true, false]\nfile_path\tString\nstatus\tString\nplatform_accession\tInteger\t[");
List<Platform> platforms = this.metadata.getPlatforms();
for (Platform obj : platforms) {
print(obj.getPlatformId() + ": " + obj.getName() + " " + obj.getInstrumentModel() + ", ");
}
print("]\n");
break;
}
case "lane": {
print("Field\tType\tPossible_Values\nname\tString\ndescription\tString\ncycle_descriptor\tString\t[e.g. {F*120}{..}{R*120}]\nskip\tBoolean\t[true, false]\nsequencer_run_accession\tInteger\nlane_number\tInteger\nstudy_type_accession\tInteger\t[");
List<Platform> platforms = this.metadata.getPlatforms();
for (Platform obj : platforms) {
print(obj.getPlatformId() + ": " + obj.getName() + " " + obj.getInstrumentModel() + ", ");
}
print("]\nlibrary_strategy_accession\tInteger\t[");
List<LibraryStrategy> objs = this.metadata.getLibraryStrategies();
for (LibraryStrategy obj : objs) {
print(obj.getLibraryStrategyId() + ": " + obj.getName() + " " + obj.getDescription() + ", ");
}
print("]\nlibrary_selection_accession\tInteger\t[");
List<LibrarySelection> libSelections = this.metadata.getLibrarySelections();
for (LibrarySelection obj : libSelections) {
print(obj.getLibrarySelectionId() + ": " + obj.getName() + " " + obj.getDescription() + ", ");
}
print("]\nlibrary_source_accession\tInteger\t[");
List<LibrarySource> libSources = this.metadata.getLibrarySource();
for (LibrarySource obj : libSources) {
print(obj.getLibrarySourceId() + ": " + obj.getName() + " " + obj.getDescription() + ", ");
}
print("]\n");
break;
}
case "ius":
print("Field\tType\tPossible_Values\nname\tString\ndescription\tString\nbarcode\tString\nskip\tBoolean\t[true, false]\nsample_accession\tInteger\nlane_accession\tInteger\n");
break;
case "workflow":
print("Field\tType\tPossible_Values\nname\tString\nversion\tString\ndescription\tString\n");
break;
case "workflow_run":
print("Field\tType\tPossible_Values\nworkflow_accession\tInteger\nstatus\tString\t[completed, failed]\nstdout\tString\nstderr\tString\n");
print(fileDescription);
print("\nThis also takes one or more --parent-accession options.\n");
print("\nThis command will result in one workflow_run, one processing tied to the parents specified, and n files attached to that processing event.\n");
break;
default:
Log.error("This tool does not know how to list the fields for the " + table + " table.");
break;
}
return (rv);
}
/**
*
* @return ReturnValue
*/
protected ReturnValue addWorkflow() {
String[] necessaryFields = { "name", "version", "description" };
if (interactive) {
print("Unfortunately interactive mode is not supported for adding workflows.");
}
// check to make sure we have what we need
ReturnValue localRet = new ReturnValue(ReturnValue.SUCCESS);
if (checkFields(necessaryFields)) {
// create a new workflow!
localRet = metadata.addWorkflow(fields.get("name"), fields.get("version"), fields.get("description"), null, null, null, null,
false, null, false, null, null, null, null);
print(String.format("Created workflow '%s' version %s with SWID: %s", fields.get("name"), fields.get("version"),
localRet.getAttribute("sw_accession")));
} else {
Log.error("You need to supply name, version, and description for the workflow table.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
}
return localRet;
}
/**
*
* @return ReturnValue
*/
protected ReturnValue addWorkflowRun() {
String[] necessaryFields = { "workflow_accession", "status" };
if (interactive) {
print("Unfortunately interactive mode is not supported for adding workflow runs and files.");
}
// check to make sure we have what we need
ReturnValue localRet = new ReturnValue(ReturnValue.SUCCESS);
if (checkFields(necessaryFields)) {
// parent accessions
int[] parents = parseParentAccessions();
// if we have parent accessions, check that they're valid right up front
if (metadata.getViaParentAccessions(parents).contains(null)) {
Log.error("parent accession invalid.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
return localRet;
}
// create a new workflow!
int workflowRunId = metadata.add_workflow_run(Integer.parseInt(fields.get("workflow_accession")));
if (workflowRunId == 0) {
Log.error("Workflow_accession invalid.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
return localRet;
}
int workflowRunAccession = metadata.get_workflow_run_accession(workflowRunId);
// create and update processing
ReturnValue metaret = metadata.add_empty_processing_event_by_parent_accession(parents);
if (metaret.getExitStatus() != ReturnValue.SUCCESS) {
Log.error("Parent_accessions invalid.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
return localRet;
}
int processingId = metaret.getReturnValue();
ReturnValue newRet = new ReturnValue();
newRet.setFiles(this.files);
// newRet.setExitStatus(fields.get("status"));
metadata.update_processing_event(processingId, newRet);
int mapProcessingIdToAccession = metadata.mapProcessingIdToAccession(processingId);
print("Created processing with SWID: " + mapProcessingIdToAccession);
print("Created workflow run with SWID: " + workflowRunAccession);
// LEFT OFF WITH: need to link process with workflow_run
metadata.update_processing_workflow_run(processingId, workflowRunAccession);
metadata.update_processing_status(processingId, ProcessingStatus.success);
// SEQWARE-1692 - need to update workflow with the status
WorkflowRun wr = metadata.getWorkflowRun(workflowRunAccession);
// add desired input files
for (Integer inputFileAccession : options.valuesOf(inputFileSpec)) {
wr.getInputFileAccessions().add(inputFileAccession);
}
String statusField = fields.get("status");
WorkflowRunStatus status = statusField == null ? null : WorkflowRunStatus.valueOf(statusField);
wr.setStatus(status);
wr.setStdOut(fields.get("stdout"));
wr.setStdErr(fields.get("stderr"));
metadata.update_workflow_run(wr.getWorkflowRunId(), wr.getCommand(), wr.getTemplate(), wr.getStatus(), wr.getStatusCmd(),
wr.getCurrentWorkingDir(), wr.getDax(), wr.getIniFile(), wr.getHost(), wr.getStdErr(), wr.getStdOut(),
wr.getWorkflowEngine(), wr.getInputFileAccessions());
} else {
Log.error("You need to supply workflow_accession and status for the workflow_run table.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
}
return localRet;
}
/**
*
* @return ReturnValue
*/
protected ReturnValue addFile() {
String[] necessaryFields = { "algorithm" };
if (interactive) {
print("Unfortunately interactive mode is not supported for adding files.");
}
// check to make sure we have what we need
ReturnValue localRet = new ReturnValue(ReturnValue.SUCCESS);
if (checkFields(necessaryFields)) {
// parent accessions
int[] parents = parseParentAccessions();
// if we have parent accessions, check that they're valid right up front
if (metadata.getViaParentAccessions(parents).contains(null)) {
Log.error("parent accession invalid.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
return localRet;
}
if (this.files.size() != 1) {
Log.error("incorrect number of files.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
return localRet;
}
// create a new file!
ReturnValue processingEventRet = metadata.add_empty_processing_event_by_parent_accession(parents);
if (processingEventRet.getExitStatus() != ReturnValue.SUCCESS) {
Log.error("Error creating processing event.");
localRet.setExitStatus(ReturnValue.FAILURE);
return localRet;
}
int procID = processingEventRet.getReturnValue();
ReturnValue newRet = new ReturnValue();
newRet.setFiles(this.files);
newRet.setAlgorithm(fields.get("algorithm"));
// send up the files via ReturnValue (ewww)
metadata.update_processing_event(procID, newRet);
metadata.update_processing_status(procID, ProcessingStatus.success);
int mapProcessingIdToAccession = metadata.mapProcessingIdToAccession(procID);
print("Created file processing with SWID: " + mapProcessingIdToAccession);
} else {
Log.error("You need to supply workflow_accession and status for the workflow_run table.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
}
return localRet;
}
/**
*
* @return ReturnValue
*/
protected ReturnValue addStudy() {
String[] necessaryFields = { "title", "description", "center_name", "center_project_name", "study_type" };
if (interactive) {
promptForStudy(necessaryFields);
}
// check to make sure we have what we need
ReturnValue localRet = new ReturnValue(ReturnValue.SUCCESS);
if (checkFields(necessaryFields)) {
// create a new study!
localRet = metadata.addStudy(fields.get("title"), fields.get("description"), fields.get("center_name"),
fields.get("center_project_name"), Integer.parseInt(fields.get("study_type")));
if (localRet.getReturnValue() == ReturnValue.INVALIDPARAMETERS) {
print("Invalid parameters, please check your id values");
return localRet;
}
print("Created study with SWID: " + localRet.getAttribute("sw_accession"));
} else {
printErrorMessage(necessaryFields, null);
// Log.error("You need to supply title, description, accession, center_name, and center_project_name for the study table along with an integer for study_type [1: Whole Genome Sequencing, 2: Metagenomics, 3: Transcriptome Analysis, 4: Resequencing, 5: Epigenetics, 6: Synthetic Genomics, 7: Forensic or Paleo-genomics, 8: Gene Regulation Study, 9: Cancer Genomics, 10: Population Genomics, 11: Other]. Alternatively, enable --interactive mode.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
}
return localRet;
}
/**
*
* @return ReturnValue
*/
protected ReturnValue addExperiment() {
String[] necessaryFields = { "study_accession", "platform_id", "title", "description" };
final String experimentLibraryDesignId = "experiment_library_design_id";
final String experimentSpotDesignId = "experiment_spot_design_id";
String[] optionalFields = { experimentLibraryDesignId, experimentSpotDesignId };
// check to make sure we have what we need
ReturnValue localRet = new ReturnValue(ReturnValue.SUCCESS);
if (interactive) {
promptForExperiment(necessaryFields);
}
for (String s : optionalFields) {
if (fields.get(s) == null) {
fields.put(s, null);
}
}
if (checkFields(necessaryFields) && nullOrLessThanZero(experimentLibraryDesignId) && nullOrLessThanZero(experimentSpotDesignId)) {
// check for valid platform id
final int platformId = Integer.parseInt(fields.get("platform_id"));
// create a new experiment
localRet = metadata.addExperiment(Integer.parseInt(fields.get("study_accession")), platformId, fields.get("description"),
fields.get("title"), parseNullOrInteger(experimentLibraryDesignId), parseNullOrInteger(experimentSpotDesignId));
if (localRet.getReturnValue() == ReturnValue.INVALIDPARAMETERS) {
print("Invalid parameters, please check your id values");
return localRet;
}
print("Created experiment with SWID: " + localRet.getAttribute("sw_accession"));
} else {
printErrorMessage(necessaryFields, null);
// Log.error("You need to supply study_accession (reported if you create a study using this tool), title, and description for the experiment table along with an integer for platform_id [9: Illumina Genome Analyzer II, 20: Illumina HiSeq 2000, 26: Illumina MiSeq]. Alternatively, enable --interactive mode.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
}
return localRet;
}
/**
*
* @return ReturnValue
*/
protected ReturnValue addSample() {
String[] necessaryFields = { "organism_id", "title", "description" };
String[] optionalFields = { "experiment_accession", "parent_sample_accession" };
// check to make sure we have what we need
ReturnValue localRet = new ReturnValue(ReturnValue.SUCCESS);
if (interactive) {
promptForSample(necessaryFields);
}
for (String s : optionalFields) {
if (fields.get(s) == null) {
fields.put(s, "0");
}
}
if (checkFields(necessaryFields)
&& (notNullOrLessThanZero("experiment_accession") || notNullOrLessThanZero("parent_sample_accession"))) {
// check for valid organism id (accession is blank and should not confuse with sw_accession)
final int organismId = Integer.parseInt(fields.get("organism_id"));
// create a new sample
localRet = metadata.addSample(Integer.parseInt(fields.get("experiment_accession")),
Integer.parseInt(fields.get("parent_sample_accession")), organismId, fields.get("description"), fields.get("title"));
if (localRet.getReturnValue() == ReturnValue.INVALIDPARAMETERS) {
print("Invalid parameters, please check your id values");
return localRet;
}
print("Created sample with SWID: " + localRet.getAttribute("sw_accession"));
} else {
printErrorMessage(necessaryFields, optionalFields);
// Log.error("You need to supply experiment_accession (reported if you create an experiment using this tool), title, and description for the sample table along with an integer for organism_id [31: Homo sapiens]. Alternatively, enable --interactive mode.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
}
return localRet;
}
private Integer parseNullOrInteger(String fieldName) {
String field = fields.get(fieldName);
if (field == null) {
return null;
} else {
return Integer.valueOf(field);
}
}
private boolean nullOrLessThanZero(String fieldName) {
boolean usable = true;
String field = fields.get(fieldName);
if (field == null) {
usable = true;
} else if (Integer.parseInt(field) <= 0) {
usable = false;
}
return usable;
}
private boolean notNullOrLessThanZero(String fieldName) {
boolean usable = true;
String field = fields.get(fieldName);
if (field == null) {
usable = false;
} else if (Integer.parseInt(field) <= 0) {
usable = false;
}
return usable;
}
/**
*
* @return ReturnValue
*
*/
protected ReturnValue addSequencerRun() {
String[] necessaryFields = { "platform_accession", "name", "description", "paired_end", "skip", "file_path" };
String[] optionalFields = { "status" };
// check to make sure we have what we need
ReturnValue localRet = new ReturnValue(ReturnValue.SUCCESS);
if (interactive) {
promptForSequencerRun(necessaryFields);
}
for (String s : optionalFields) {
if (fields.get(s) == null) {
fields.put(s, null);
}
}
if (checkFields(necessaryFields)) {
// create a new experiment
localRet = metadata.addSequencerRun(Integer.parseInt(fields.get("platform_accession")), fields.get("name"), fields
.get("description"), "true".equalsIgnoreCase(fields.get("paired_end")), "true".equalsIgnoreCase(fields.get("skip")),
fields.get("file_path"), fields.get("status") == null ? null : SequencerRunStatus.valueOf(fields.get("status")));
print("Created sequencer run with SWID: " + localRet.getAttribute("sw_accession"));
} else {
printErrorMessage(necessaryFields, optionalFields);
// Log.error("You need to supply name, description, platform_accession [see platform lookup], the complete file path of the run, and 'true' or 'false' for paired_end and skip. Alternatively, enable --interactive mode.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
}
return localRet;
}
protected ReturnValue addLane() {
String[] necessaryFields = { "sequencer_run_accession", "study_type_accession", "library_strategy_accession",
"library_selection_accession", "library_source_accession", "name", "description", "cycle_descriptor", "lane_number", "skip" };
// check to make sure we have what we need
ReturnValue localRet = new ReturnValue(ReturnValue.SUCCESS);
if (interactive) {
promptForLane(necessaryFields);
}
if (checkFields(necessaryFields)) {
// note, study type has no accession in the database
final int studyTypeId = Integer.parseInt(fields.get("study_type_accession"));
// create a new experiment
localRet = metadata.addLane(Integer.parseInt(fields.get("sequencer_run_accession")), studyTypeId,
Integer.parseInt(fields.get("library_strategy_accession")),
Integer.parseInt(fields.get("library_selection_accession")), Integer.parseInt(fields.get("library_source_accession")),
fields.get("name"), fields.get("description"), fields.get("cycle_descriptor"),
"true".equalsIgnoreCase(fields.get("skip")), Integer.parseInt(fields.get("lane_number")));
if (localRet.getReturnValue() == ReturnValue.INVALIDPARAMETERS) {
print("Invalid parameters, please check your id values");
return localRet;
}
print("Created lane with SWID: " + localRet.getAttribute("sw_accession"));
} else {
printErrorMessage(necessaryFields, null);
// Log.error("You need to supply name, description, cycle_descriptor [e.g. {F*120}{..}{R*120}], sequencer_run_accession, study_type_accession, library_strategy_accession, library_selection_accession, library_source_accession and 'true' or 'false' for skip. Alternatively, enable --interactive mode.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
}
return localRet;
}
protected ReturnValue addIUS() {
String[] necessaryFields = { "lane_accession", "sample_accession", "name", "description", "skip", "barcode" };
// check to make sure we have what we need
ReturnValue localRet = new ReturnValue(ReturnValue.SUCCESS);
if (interactive) {
promptForIUS(necessaryFields);
}
// Integer laneId, Integer sampleId, String name, String description, String cycleDescriptor, boolean skip
if (checkFields(necessaryFields)) {
// allow barcode to be empty
// create a new experiment
localRet = metadata.addIUS(Integer.parseInt(fields.get("lane_accession")), Integer.parseInt(fields.get("sample_accession")),
fields.get("name"), fields.get("description"), fields.get("barcode"), "true".equalsIgnoreCase(fields.get("skip")));
if (localRet.getReturnValue() == ReturnValue.INVALIDPARAMETERS) {
print("Invalid parameters, please check your id values");
return localRet;
}
print("Created IUS with SWID: " + localRet.getAttribute("sw_accession"));
} else {
printErrorMessage(necessaryFields, null);
// Log.error("You need to supply name, description, lane_accession, sample_accession, barcode and 'true' or 'false' for skip. Alternatively, enable --interactive mode.");
localRet.setExitStatus(ReturnValue.INVALIDPARAMETERS);
}
return localRet;
}
private void printErrorMessage(String[] requiredFields, String[] optionalFields) {
StringBuilder sb = new StringBuilder();
sb.append("Insufficient fields supplied.");
sb.append("\nRequired fields:");
for (String s : requiredFields) {
sb.append("\n\t").append(s);
}
if (optionalFields != null) {
sb.append("\nOptional fields:");
for (String s : optionalFields) {
sb.append("\n\t").append(s);
}
}
sb.append("\nFor more information about these options, run with the --list-fields switch.");
sb.append("\nAlternatively, enable --interactive mode.");
Log.error(sb.toString());
Log.stdout("You supplied:");
printFields();
}
/**
* {@inheritDoc}
*
* @param string
*/
@Override
public void print(String string) {
if (bw != null) {
try {
bw.write(string);
} catch (IOException ex) {
Log.error(null, ex);
}
} else {
System.out.println(string);
}
}
/**
*
* @return ReturnValue
*/
protected ReturnValue parseFields() {
ReturnValue localRet = new ReturnValue(ReturnValue.SUCCESS);
List<?> valuesOf = options.valuesOf("field");
for (Object value : valuesOf) {
String[] t = value.toString().split("::");
if (t.length == 2) {
fields.put(t[0], t[1]);
Log.info(" Field: " + t[0] + " value " + t[1]);
}
}
return localRet;
}
protected ReturnValue parseFiles() {
ReturnValue localRet = new ReturnValue(ReturnValue.SUCCESS);
List<?> valuesOf = options.valuesOf("file");
for (Object value : valuesOf) {
FileMetadata f = Metadata.fileString2FileMetadata(value.toString());
if (f != null) {
files.add(f);
} else {
print("You need to encode the file as '<type>::<file-meta-type>::<file-path>'\n");
}
}
return localRet;
}
protected int[] parseParentAccessions() {
List<?> valuesOf = options.valuesOf("parent-accession");
ArrayList<Integer> parents = new ArrayList<>();
for (Object value : valuesOf) {
parents.add(Integer.parseInt(value.toString()));
}
int[] localRet = new int[parents.size()];
for (int i = 0; i < localRet.length; i++) {
localRet[i] = parents.get(i);
}
return localRet;
}
/**
* {@inheritDoc}
*
* @return
*/
@Override
public ReturnValue clean_up() {
this.closeBufferWriter();
return ret;
}
/**
* {@inheritDoc}
*
* @return
*/
@Override
public String get_description() {
return "This plugin lets you list, read, and write to a collection of tables in the underlying MetaDB. "
+ "This makes it easier to automate the creation of entities in the database which can be used as "
+ "parents for file uploads and launched workflows.";
}
protected void closeBufferWriter() {
try {
if (this.bw != null) {
this.bw.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public boolean checkFields(String[] fs) {
boolean allPresent = true;
for (String s : fs) {
if (!fields.containsKey(s)) {
allPresent = false;
Log.debug(s + " <null>");
} else {
Log.debug(s + " " + fields.get(s));
}
}
return allPresent;
}
private void printFields() {
for (String s : fields.keySet()) {
Log.stdout(s + "=" + fields.get(s));
}
}
// //////////////////////////////////////////////////////////////////////////
// /// Interactive code
// //////////////////////////////////////////////////////////////////////////
protected void promptForStudy(String[] necessaryFields) {
Log.stdout("---Create a study---");
if (!fields.containsKey("study_type")) {
System.out.println();
for (StudyType st : metadata.getStudyTypes()) {
Log.stdout(st.toString());
}
promptInteger("study_type", 4);
}
promptForFields(necessaryFields);
if (!fieldsConfirmed(necessaryFields)) {
promptForStudy(necessaryFields);
}
}
protected void promptForSample(String[] necessaryFields) {
Log.stdout("---Create a sample---");
int checkMe;
if (!fields.containsKey("experiment_accession")) {
promptInteger("experiment_accession", 0);
}
if (!fields.containsKey("parent_sample_accession")) {
promptInteger("parent_sample_accession", 0);
}
checkMe = Integer.parseInt(fields.get("experiment_accession")) + Integer.parseInt(fields.get("parent_sample_accession"));
if (!fields.containsKey("organism_id")) {
System.out.println();
for (Organism o : metadata.getOrganisms()) {
Log.stdout(o.toString());
}
promptInteger("organism_id", 31);
}
promptForFields(necessaryFields);
if (!fieldsConfirmed(necessaryFields) || checkMe <= 0) {
if (checkMe <= 0) {
Log.stdout("You must provide experiment_accession and/or parent_sample_accession.");
}
promptForSample(necessaryFields);
}
}
protected void promptForSequencerRun(String[] necessaryFields) {
Log.stdout("---Create a sequencer run---");
if (!fields.containsKey("platform_accession")) {
System.out.println();
for (Platform p : metadata.getPlatforms()) {
Log.stdout(p.toString());
}
promptInteger("platform_accession", 20);
}
if (!fields.containsKey("paired_end")) {
promptBoolean("paired_end", true);
}
if (!fields.containsKey("skip")) {
promptBoolean("skip", false);
}
promptForFields(necessaryFields);
if (!fieldsConfirmed(necessaryFields)) {
promptForSequencerRun(necessaryFields);
}
}
protected void promptForExperiment(String[] necessaryFields) {
Log.stdout("---Create an experiment---");
if (!fields.containsKey("platform_id")) {
System.out.println();
for (Platform p : metadata.getPlatforms()) {
Log.stdout(p.toString());
}
promptInteger("platform_id", 20);
}
promptForFields(necessaryFields);
if (!fieldsConfirmed(necessaryFields)) {
promptForExperiment(necessaryFields);
}
}
protected void promptForLane(String[] necessaryFields) {
Log.stdout("---Create a lane---");
if (!fields.containsKey("sequencer_run_accession")) {
promptInteger("sequencer_run_accession", null);
}
if (!fields.containsKey("study_type_accession")) {
System.out.println();
for (StudyType st : metadata.getStudyTypes()) {
Log.stdout(st.toString());
}
promptInteger("study_type_accession", 4);
}
if (!fields.containsKey("library_strategy_accession")) {
System.out.println();
for (LibraryStrategy st : metadata.getLibraryStrategies()) {
Log.stdout(st.toString());
}
promptInteger("library_strategy_accession", null);
}
if (!fields.containsKey("library_selection_accession")) {
System.out.println();
for (LibrarySelection st : metadata.getLibrarySelections()) {
Log.stdout(st.toString());
}
promptInteger("library_selection_accession", null);
}
if (!fields.containsKey("library_source_accession")) {
System.out.println();
for (LibrarySource st : metadata.getLibrarySource()) {
Log.stdout(st.toString());
}
promptInteger("library_source_accession", null);
}
if (!fields.containsKey("lane_number")) {
promptInteger("lane_number", 1);
}
if (!fields.containsKey("skip")) {
promptBoolean("skip", false);
}
promptForFields(necessaryFields);
if (!fieldsConfirmed(necessaryFields)) {
promptForLane(necessaryFields);
}
}
protected void promptForIUS(String[] necessaryFields) {
Log.stdout("---Create a IUS/barcode---");
if (!fields.containsKey("lane_accession")) {
promptInteger("lane_accession", null);
}
if (!fields.containsKey("sample_accession")) {
promptInteger("sample_accession", null);
}
if (!fields.containsKey("skip")) {
promptBoolean("skip", false);
}
promptForFields(necessaryFields);
if (!fieldsConfirmed(necessaryFields)) {
promptForIUS(necessaryFields);
}
}
protected void promptForFields(String[] fs) {
for (String s : fs) {
if (!fields.containsKey(s)) {
promptString(s, null);
}
}
}
protected String promptString(String string, String deflt) {
String title = ConsoleAdapter.getInstance().promptString(string, deflt);
fields.put(string, title);
return title;
}
protected Integer promptInteger(String string, Integer deflt) {
Integer title = ConsoleAdapter.getInstance().promptInteger(string, deflt);
fields.put(string, title.toString());
return title;
}
protected Boolean promptBoolean(String string, Boolean deflt) {
Boolean title = ConsoleAdapter.getInstance().promptBoolean(string, deflt);
fields.put(string, title.toString());
return title;
}
protected boolean fieldsConfirmed(String[] necessaryFields) {
for (String s : necessaryFields) {
Log.stdout(s + " : " + fields.get(s));
}
String confirm = ConsoleAdapter.getInstance().readLine("Is this information correct? [y/n] :");
// System.out.println("result: " + confirm);
if (confirm.trim().toLowerCase().equals("y") || confirm.trim().toLowerCase().equals("yes") || confirm.trim().isEmpty()) {
return true;
} else {
fields.clear();
parseFields();
return false;
}
}
public static FileMetadata fileString2FileMetadata(String fileString) {
FileMetadata fm = null;
String[] tokens = fileString.split("::");
if (tokens.length > 0) {
fm = new FileMetadata();
fm.setType(tokens[0]);
if (tokens.length > 1) {
fm.setMetaType(tokens[1]);
if (tokens.length > 2) {
fm.setFilePath(tokens[2]);
if (tokens.length > 3) {
fm.setDescription(tokens[3]);
}
}
}
}
return fm;
}
}