/*
* 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 com.google.common.collect.Lists;
import io.seqware.common.model.ProcessingStatus;
import io.seqware.common.model.WorkflowRunStatus;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import joptsimple.OptionSpec;
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.pipeline.plugin.Plugin;
import net.sourceforge.seqware.pipeline.plugin.PluginInterface;
import net.sourceforge.seqware.pipeline.plugins.filelinker.FileLinkerParser;
import org.openide.util.lookup.ServiceProvider;
/**
*
* <p>
* FileLinker class.
* </p>
*
* @author mtaschuk
* @version $Id: $Id
*/
@ServiceProvider(service = PluginInterface.class)
public class FileLinker extends Plugin {
ReturnValue ret = new ReturnValue();
private final OptionSpec<String> separator;
public FileLinker() {
super();
parser.acceptsAll(
Arrays.asList("file-list-file"),
"A file containing the necessary information, with each line in the format parent_sw_accession, file path and mime-type. parent_sw_accession is either an IUS or a Lane.")
.withRequiredArg();
parser.acceptsAll(Arrays.asList("workflow-accession"), "The sw_accession of the Import files workflow").withRequiredArg();
this.separator = parser.accepts("csv-separator").withOptionalArg().ofType(String.class).defaultsTo("\t")
.describedAs("Separator used in csv file.");
ret.setExitStatus(ReturnValue.SUCCESS);
}
@Override
public ReturnValue init() {
return ret;
}
@Override
public ReturnValue do_test() {
return ret;
}
@Override
public ReturnValue do_run() {
final String currentDir = new File(".").getAbsolutePath();
if (options.has("file-list-file") && options.has("workflow-accession")) {
// parse the file
String filename = (String) options.valueOf("file-list-file");
Map<Integer, List<FileMetadata>> swaToFileMap;
try {
swaToFileMap = FileLinkerParser.parse(filename, separator.value(options).charAt(0));
} catch (FileNotFoundException e) {
ret.setExitStatus(ReturnValue.INVALIDFILE);
ret.setDescription(e.getMessage());
return ret;
} catch (UnsupportedEncodingException e) {
ret.setExitStatus(ReturnValue.FILENOTREADABLE);
ret.setDescription(e.getMessage());
return ret;
}
final int workflowAccession = Integer.valueOf(options.valueOf("workflow-accession").toString());
for (Map.Entry<Integer, List<FileMetadata>> entry : swaToFileMap.entrySet()) {
// seqware-1938
// pre-emptively check whether there are any valid files, skip workflow run creation if there are not
List<FileMetadata> files = removeFilesThatAlreadyExistInSeqWare(entry.getValue());
if (files.isEmpty()) {
Log.stdout("No files to add for IUS " + entry.getKey() + " skipping.");
continue;
}
// Make the workflow run, one for every IUS.
int workflowRunId = metadata.add_workflow_run(workflowAccession);
if (workflowRunId == 0) {
Log.error("Failure to create a new workflow run id. Value is " + workflowRunId
+ ". The workflow_run accession may be incorrect.");
ret.setExitStatus(ReturnValue.SQLQUERYFAILED);
return ret;
}
try {
if (!metadata.linkWorkflowRunAndParent(workflowRunId, entry.getKey())) {
Log.error("Incorrect ius or lane accession");
ret.setExitStatus(ReturnValue.INVALIDPARAMETERS);
return ret;
}
} catch (SQLException ex) {
Log.fatal("SQLException", ex);
ret.setExitStatus(ReturnValue.SQLQUERYFAILED);
return ret;
}
if (!saveFiles(workflowRunId, entry.getKey(), files)) {
return ret;
}
// Update the workflow run to reflect success.
ReturnValue rv = metadata.update_workflow_run(workflowRunId, null, null, WorkflowRunStatus.completed, null, currentDir,
null, null, null, null, null, null, null);
print("SWID: " + rv.getReturnValue() + "\n");
if (rv.getExitStatus() != ReturnValue.SUCCESS) {
Log.error("Failure in updating the workflow run " + workflowRunId + ". The workflow_run accession may be incorrect.");
ret.setExitStatus(ReturnValue.FAILURE);
return ret;
}
}
} else {
println("Combination of parameters not recognized!");
println(this.get_syntax());
ret.setExitStatus(ReturnValue.INVALIDPARAMETERS);
}
return ret;
}
private boolean saveFiles(int workflowRunId, int iusSwa, List<FileMetadata> inputFiles) {
boolean result = true;
assert (!inputFiles.isEmpty()); // also, we've already removed files that already exist
boolean success = createFileImportProcessingNode(iusSwa, inputFiles, workflowRunId);
if (!success) {
return false;
}
return result;
}
private List<FileMetadata> removeFilesThatAlreadyExistInSeqWare(List<FileMetadata> files) {
List<FileMetadata> result = Lists.newArrayList();
for (FileMetadata file : files) {
if (!metadata.isDuplicateFile(file.getFilePath())) {
result.add(file);
} else {
Log.error("Ignored file [" + file.getFilePath() + "]. Already exists in database.");
}
}
return result;
}
private boolean createFileImportProcessingNode(int iusSwa, List<FileMetadata> files, int workflowRunId) {
ReturnValue processingReturnValue = new ReturnValue(ReturnValue.SUCCESS);
int processingId = metadata.add_empty_processing_event_by_parent_accession(new int[] { iusSwa }).getReturnValue();
processingReturnValue.setAlgorithm("fileImport");
for (FileMetadata file : files) {
processingReturnValue.getFiles().add(file);
Log.info("Attempting to add file [" + file.getFilePath() + "] with meta data type [" + file.getMetaType()
+ "] to database. SeqWare Accession [" + iusSwa + "].");
}
metadata.update_processing_workflow_run(processingId, metadata.get_workflow_run_accession(workflowRunId));
metadata.update_processing_event(processingId, processingReturnValue);
metadata.update_processing_status(processingId, ProcessingStatus.success);
return true;
}
@Override
public ReturnValue clean_up() {
return ret;
}
@Override
public String get_description() {
return "Takes a list of files and enters them into the database, linking "
+ "them with the appropriate IUSes and creating workflow runs for "
+ "the 'FileImport' workflow. For more information, see http://seqware.github.com/docs/22-filelinker/";
}
}