package net.sourceforge.seqware.pipeline.plugins.checkdb;
import io.seqware.pipeline.SqwKeys;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import net.sourceforge.seqware.common.factory.DBAccess;
import net.sourceforge.seqware.common.metadata.Metadata;
import net.sourceforge.seqware.common.metadata.MetadataFactory;
import net.sourceforge.seqware.common.model.Experiment;
import net.sourceforge.seqware.common.model.IUS;
import net.sourceforge.seqware.common.model.Lane;
import net.sourceforge.seqware.common.model.Processing;
import net.sourceforge.seqware.common.model.Sample;
import net.sourceforge.seqware.common.model.SequencerRun;
import net.sourceforge.seqware.common.model.Study;
import net.sourceforge.seqware.common.model.Workflow;
import net.sourceforge.seqware.common.model.WorkflowRun;
import net.sourceforge.seqware.common.module.ReturnValue;
import net.sourceforge.seqware.common.util.Log;
import net.sourceforge.seqware.common.util.configtools.ConfigTools;
import net.sourceforge.seqware.pipeline.plugin.Plugin;
import net.sourceforge.seqware.pipeline.plugin.PluginInterface;
import net.sourceforge.seqware.pipeline.plugins.checkdb.CheckDBPluginInterface.Level;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.openide.util.Lookup;
import org.openide.util.lookup.ServiceProvider;
import org.rendersnake.HtmlCanvas;
/**
* A database validation tool for your SeqWare metadb
*
* @author dyuen ProviderFor(PluginInterface.class)
* @version $Id: $Id
*/
@ServiceProvider(service = PluginInterface.class)
public final class CheckDB extends Plugin {
public static final int NUMBER_TO_OUTPUT = 100;
/**
* <p>
* Constructor for HelloWorld.
* </p>
*/
public CheckDB() {
super();
parser.acceptsAll(Arrays.asList("help", "h", "?"), "Provides this help message.");
}
/*
* (non-Javadoc)
*
* @see net.sourceforge.seqware.pipeline.plugin.PluginInterface#init()
*/
/**
* {@inheritDoc}
*
* @return
*/
@Override
public final ReturnValue init() {
try {
HashMap<String, String> settings = (HashMap<String, String>) ConfigTools.getSettings();
if (!ConfigTools.isValidDBConnectionParam(settings)) {
ReturnValue ret = new ReturnValue();
System.out.println(MetadataFactory.NO_DATABASE_CONFIG);
ret.setExitStatus(ReturnValue.SETTINGSFILENOTFOUND);
return ret;
}
} catch (Exception e) {
ReturnValue ret = new ReturnValue();
ret.setExitStatus(ReturnValue.SETTINGSFILENOTFOUND);
return ret;
}
return new ReturnValue();
}
/*
* (non-Javadoc)
*
* @see net.sourceforge.seqware.pipeline.plugin.PluginInterface#do_test()
*/
/**
* {@inheritDoc}
*
* @return
*/
@Override
public ReturnValue do_test() {
// TODO Auto-generated method stub
return new ReturnValue();
}
/*
* (non-Javadoc)
*
* @see net.sourceforge.seqware.pipeline.plugin.PluginInterface#do_run()
*/
/**
* {@inheritDoc}
*
* @return
*/
@Override
public final ReturnValue do_run() {
ReturnValue ret = new ReturnValue();
Collection<CheckDBPluginInterface> plugins = (Collection<CheckDBPluginInterface>) Lookup.getDefault().lookupAll(
CheckDBPluginInterface.class);
Map<CheckDBPluginInterface, SortedMap<CheckDBPluginInterface.Level, Set<String>>> resultMap = new HashMap<>();
for (CheckDBPluginInterface plugin : plugins) {
SortedMap<Level, Set<String>> result = new TreeMap<>();
for (Level l : CheckDBPluginInterface.Level.values()) {
result.put(l, new HashSet<String>());
}
Log.info("Running " + plugin.getClass().getSimpleName());
try {
plugin.check(new SelectQueryRunner(DBAccess.get()), result);
resultMap.put(plugin, result);
} catch (Exception e) {
Log.fatal("Plugin " + plugin.getClass().getSimpleName() + " died", e);
if (!result.containsKey(Level.SEVERE)) {
// defensive check in case plugin author decided to corrupt the map
result.put(Level.SEVERE, new HashSet<String>());
}
resultMap.get(plugin).get(Level.SEVERE).add("Plugin threw an exception and died");
resultMap.put(plugin, result);
}
}
// presumably, we would reformat resultMap and create a nice HTML report here
HtmlCanvas html = new HtmlCanvas();
try {
html.html().body().h1().content(this.getClass().getSimpleName() + " Report");
for (Entry<CheckDBPluginInterface, SortedMap<CheckDBPluginInterface.Level, Set<String>>> pluginEntry : resultMap.entrySet()) {
html.h2().content(pluginEntry.getKey().getClass().getSimpleName());
for (Entry<CheckDBPluginInterface.Level, Set<String>> warning : pluginEntry.getValue().entrySet()) {
html.h3().content(warning.getKey().name());
html.ol();
for (String entry : warning.getValue()) {
html.li().content(entry, false);
// html.li().content(entry);
}
html._ol();
}
}
html._body()._html();
File createTempFile = File.createTempFile("report", ".html");
FileUtils.write(createTempFile, html.toHtml());
Log.stdout("Printed report to " + createTempFile.getAbsolutePath());
ret.setUrl(createTempFile.toURI().toURL().toString());
} catch (IOException ex) {
Log.fatal("Could not render HTML report", ex);
ret.setExitStatus(ReturnValue.FAILURE);
}
return ret;
}
/**
* <p>
* get_description.
* </p>
*
* @return a {@link java.lang.String} object.
*/
@Override
public final String get_description() {
return ("A database validation tool for your SeqWare metadb.");
}
public static void main(String[] args) throws IOException, URISyntaxException {
CheckDB mp = new CheckDB();
mp.init();
List<String> arr = new ArrayList<>();
mp.setParams(arr);
mp.parse_parameters();
ReturnValue doRun = mp.do_run();
Desktop.getDesktop().browse(new URI(doRun.getUrl()));
}
@Override
public final ReturnValue clean_up() {
return new ReturnValue();
}
/**
* Convenience method for processing output and appending it to the warning map
*
* @param result
* a sorted map where results can be appended
* @param level
* Level of message to create
* @param description
* A description of the sw_accessions to be reported from list
* @param list
* a list of sw_accessions to report
*/
public static void processOutput(SortedMap<Level, Set<String>> result, Level level, String description, List<Integer> list) {
if (list.size() > 0) {
String swRestUrl = ConfigTools.getSettings().get(SqwKeys.SW_REST_URL.getSettingKey());
Metadata md = MetadataFactory.get(ConfigTools.getSettings());
Collections.sort(list);
// shorten list if required
List<Integer> outputList = new ArrayList<>(list);
if (list.size() > NUMBER_TO_OUTPUT) {
outputList = outputList.subList(0, NUMBER_TO_OUTPUT);
}
StringBuilder warnings = new StringBuilder();
warnings.append(description);
int[] parentAccessions = ArrayUtils.toPrimitive(outputList.toArray(new Integer[outputList.size()]));
List<Object> parentModels = md.getViaAccessions(parentAccessions);
// let's try constructing hyperlinks here
for (int i = 0; i < parentModels.size(); i++) {
String url = null;
if (parentModels.get(i) instanceof Experiment) {
url = swRestUrl + "/experiments/" + parentAccessions[i];
} else if (parentModels.get(i) instanceof net.sourceforge.seqware.common.model.File) {
url = swRestUrl + "/files/" + parentAccessions[i];
} else if (parentModels.get(i) instanceof IUS) {
url = swRestUrl + "/ius/" + parentAccessions[i];
} else if (parentModels.get(i) instanceof Lane) {
url = swRestUrl + "/lanes/" + parentAccessions[i];
} else if (parentModels.get(i) instanceof Processing) {
url = swRestUrl + "/processes/" + parentAccessions[i];
} else if (parentModels.get(i) instanceof Sample) {
url = swRestUrl + "/samples/" + parentAccessions[i];
} else if (parentModels.get(i) instanceof SequencerRun) {
url = swRestUrl + "/sequencerruns/" + parentAccessions[i];
} else if (parentModels.get(i) instanceof Study) {
url = swRestUrl + "/studies/" + parentAccessions[i];
} else if (parentModels.get(i) instanceof WorkflowRun) {
url = swRestUrl + "/workflowruns/" + parentAccessions[i];
} else if (parentModels.get(i) instanceof Workflow) {
url = swRestUrl + "/workflows/" + parentAccessions[i];
}
if (url != null) {
warnings.append(" <a href=\"").append(url).append("\">").append(parentAccessions[i]).append("</a> ");
} else {
warnings.append(parentAccessions[i]);
}
if (i != parentModels.size() - 1) {
warnings.append(',');
}
}
if (list.size() != outputList.size()) {
warnings.append(" (Truncated, ").append(list.size()).append(" in total)");
}
result.get(level).add(warnings.toString());
}
}
}