/*
* Copyright 2015-2016 OpenCB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.opencb.opencga.analysis;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.opencb.opencga.analysis.execution.plugins.OpenCGAAnalysis;
import org.opencb.opencga.analysis.execution.plugins.PluginFactory;
import org.opencb.opencga.catalog.models.tool.Execution;
import org.opencb.opencga.catalog.models.tool.Manifest;
import org.opencb.opencga.catalog.models.tool.Option;
import org.opencb.opencga.core.common.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
public class ToolManager {
protected static Logger logger = LoggerFactory.getLogger(ToolManager.class);
protected final Properties analysisProperties;
protected final String home;
protected String analysisName;
protected String executionName;
protected Path analysisRootPath;
protected Path analysisPath;
protected Path manifestFile;
protected Path resultsFile;
protected String sessionId;
protected Manifest manifest;
protected Execution execution;
protected boolean plugin;
protected static ObjectMapper jsonObjectMapper = new ObjectMapper();
private ToolManager() throws IOException, AnalysisExecutionException {
home = Config.getOpenCGAHome();
analysisProperties = Config.getAnalysisProperties();
executionName = null;
}
public ToolManager(String analysisStr, String execution) throws IOException, AnalysisExecutionException {
this(analysisStr, execution, "system");
}
@Deprecated
public ToolManager(String analysisStr, String execution, String analysisOwner) throws IOException, AnalysisExecutionException {
this();
if (analysisOwner.equals("system")) {
this.analysisRootPath = Paths.get(analysisProperties.getProperty("OPENCGA.ANALYSIS.BINARIES.PATH"));
} else {
this.analysisRootPath = Paths.get(home, "accounts", analysisOwner);
}
this.analysisName = analysisStr;
if (analysisName.contains(".")) {
executionName = analysisName.split("\\.")[1];
analysisName = analysisName.split("\\.")[0];
} else {
executionName = execution;
}
load();
}
public ToolManager(Path analysisRootPath, String analysisName, String executionName) throws IOException, AnalysisExecutionException {
this();
this.analysisRootPath = analysisRootPath;
this.analysisName = analysisName;
this.executionName = executionName;
load();
}
private void load() throws IOException, AnalysisExecutionException {
analysisPath = Paths.get(home).resolve(analysisRootPath).resolve(analysisName);
if (!analysisPath.toFile().exists()) {
//Search for a plugin
OpenCGAAnalysis plugin = PluginFactory.get().getPlugin(analysisName);
if (plugin == null) {
throw new IllegalArgumentException("Plugin '" + analysisName + "' does not exist");
}
manifest = plugin.getManifest();
execution = getExecution();
this.plugin = true;
} else {
manifestFile = analysisPath.resolve(Paths.get("manifest.json"));
resultsFile = analysisPath.resolve(Paths.get("results.js"));
manifest = getManifest();
execution = getExecution();
}
}
/*
* CommandLine creation methods
*/
private boolean checkRequiredParams(Map<String, List<String>> params, List<Option> validParams) {
for (Option param : validParams) {
if (param.isRequired() && !params.containsKey(param.getName())) {
System.out.println("Missing param: " + param);
return false;
}
}
return true;
}
private Map<String, List<String>> removeUnknownParams(Map<String, List<String>> params, List<Option> validOptions) {
Set<String> validKeyParams = new HashSet<String>();
for (Option param : validOptions) {
validKeyParams.add(param.getName());
}
Map<String, List<String>> paramsCopy = new HashMap<String, List<String>>(params);
for (String param : params.keySet()) {
if (!validKeyParams.contains(param)) {
paramsCopy.remove(param);
}
}
return paramsCopy;
}
public String createCommandLine(Map<String, List<String>> params)
throws AnalysisExecutionException {
return createCommandLine(execution.getExecutable(), params);
}
public String createCommandLine(String executable, Map<String, List<String>> params)
throws AnalysisExecutionException {
logger.debug("params received in createCommandLine: " + params);
String binaryPath = analysisPath.resolve(executable).toString();
// Check required params
List<Option> validParams = new LinkedList<>(execution.getValidParams());
validParams.addAll(manifest.getGlobalParams());
validParams.add(new Option(execution.getOutputParam(), "Outdir", false));
if (checkRequiredParams(params, validParams)) {
params = new HashMap<>(removeUnknownParams(params, validParams));
} else {
throw new AnalysisExecutionException("ERROR: missing some required params.");
}
StringBuilder cmdLine = new StringBuilder();
cmdLine.append(binaryPath);
if (params.containsKey("tool")) {
String tool = params.get("tool").get(0);
cmdLine.append(" --tool ").append(tool);
params.remove("tool");
}
for (String key : params.keySet()) {
// Removing renato param
if (!key.equals("renato")) {
if (key.length() == 1) {
cmdLine.append(" -").append(key);
} else {
cmdLine.append(" --").append(key);
}
if (params.get(key) != null) {
String paramsArray = params.get(key).toString();
String paramValue = paramsArray.substring(1, paramsArray.length() - 1).replaceAll("\\s", "");
cmdLine.append(" ").append(paramValue);
}
}
}
return cmdLine.toString();
}
/*
* Execute util methods
* Will create the required ExecutorManager and run the job
*/
public String getAnalysisName() {
return analysisName;
}
public boolean isPlugin() {
return plugin;
}
public Manifest getManifest() throws IOException, AnalysisExecutionException {
if (manifest == null) {
manifest = jsonObjectMapper.readValue(manifestFile.toFile(), Manifest.class);
// analysis = gson.fromJson(IOUtils.toString(manifestFile.toFile()), Analysis.class);
}
return manifest;
}
public Execution getExecution() {
if (execution == null) {
if (executionName == null || executionName.isEmpty()) {
execution = manifest.getExecutions().get(0);
} else {
for (Execution exe : manifest.getExecutions()) {
if (exe.getId().equalsIgnoreCase(executionName)) {
execution = exe;
break;
}
}
if (execution == null) {
throw new IllegalArgumentException("Unknown execution name : " + executionName);
}
}
}
return execution;
}
public String getExamplePath(String fileName) {
return analysisPath.resolve("examples").resolve(fileName).toString();
}
public String help(String baseUrl) {
if (!Files.exists(manifestFile)) {
return "Manifest for " + analysisName + " not found.";
}
String execName = "";
if (executionName != null)
execName = "." + executionName;
StringBuilder sb = new StringBuilder();
sb.append("Analysis: " + manifest.getName() + "\n");
sb.append("Description: " + manifest.getDescription() + "\n");
sb.append("Version: " + manifest.getVersion() + "\n\n");
sb.append("Author: " + manifest.getAuthor().getName() + "\n");
sb.append("Email: " + manifest.getAuthor().getEmail() + "\n");
if (!manifest.getWebsite().equals(""))
sb.append("Website: " + manifest.getWebsite() + "\n");
if (!manifest.getPublication().equals(""))
sb.append("Publication: " + manifest.getPublication() + "\n");
sb.append("\nUsage: \n");
sb.append(baseUrl + "analysis/" + analysisName + execName + "/{action}?{params}\n\n");
sb.append("\twhere: \n");
sb.append("\t\t{action} = [run, help, params, test, status]\n");
sb.append("\t\t{params} = " + baseUrl + "analysis/" + analysisName + execName + "/params\n");
return sb.toString();
}
public String params() {
if (!Files.exists(manifestFile)) {
return "Manifest for " + analysisName + " not found.";
}
if (execution == null) {
return "ERROR: Executable not found.";
}
StringBuilder sb = new StringBuilder();
sb.append("Valid params for " + manifest.getName() + ":\n\n");
for (Option param : execution.getValidParams()) {
String required = "";
if (param.isRequired())
required = "*";
sb.append("\t" + param.getName() + ": " + param.getDescription() + " " + required + "\n");
}
sb.append("\n\t*: required parameters.\n");
return sb.toString();
}
public String test(String jobName, int jobId, String jobFolder) throws AnalysisExecutionException, IOException {
// TODO test
if (!Files.exists(manifestFile)) {
return "Manifest for " + analysisName + " not found.";
}
if (execution == null) {
return "ERROR: Executable not found.";
}
// executeCommandLine(execution.getTestCmd(), jobName, jobId, jobFolder, analysisName);
// executeLocal();
return String.valueOf(jobName);
}
public String getResult() throws AnalysisExecutionException {
return execution.getResult();
}
public InputStream getResultInputStream() throws AnalysisExecutionException, IOException {
System.out.println(resultsFile.toAbsolutePath().toString());
if (!Files.exists(resultsFile)) {
resultsFile = analysisPath.resolve(Paths.get("results.js"));
}
if (Files.exists(resultsFile)) {
return Files.newInputStream(resultsFile);
}
throw new AnalysisExecutionException("result.js not found.");
}
}