/*
* Eoulsan development code
*
* This code may be freely distributed and modified under the
* terms of the GNU Lesser General Public License version 2.1 or
* later and CeCILL-C. This should be distributed with the code.
* If you do not have a copy, see:
*
* http://www.gnu.org/licenses/lgpl-2.1.txt
* http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.txt
*
* Copyright for this code is held jointly by the Genomic platform
* of the Institut de Biologie de l'École normale supérieure and
* the individual authors. These should be listed in @author doc
* comments.
*
* For more information on the Eoulsan project and its aims,
* or to join the Eoulsan Google group, visit the home page
* at:
*
* http://outils.genomique.biologie.ens.fr/eoulsan
*
*/
package fr.ens.biologie.genomique.eoulsan.galaxytools;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.python.core.PyDictionary;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.util.PythonInterpreter;
import com.google.common.base.Splitter;
import fr.ens.biologie.genomique.eoulsan.EoulsanException;
import fr.ens.biologie.genomique.eoulsan.util.GuavaCompatibility;
/**
* This class create a Cheetah interpreter, it can build a command line tool
* from command tag from Galaxy tool XML file.
* @author Sandrine Perrin
* @since 2.0
*/
public class CheetahInterpreter {
/** The Constant VAR_CMD_NAME. */
public static final String VAR_CMD_NAME = "cmd";
/** The Constant INSTANCE_NAME. */
public static final String PYTHON_VARIABLES_DICT_NAME = "galaxy_dict";
/** The Constant CALL_METHOD. */
public static final String CALL_METHOD = PYTHON_VARIABLES_DICT_NAME + ".get";
/** The Constant DEFAULT_VALUE_NULL. */
static final String DEFAULT_VALUE_NULL = "no_authorized";
private final String cheetahScript;
private final Map<String, String> variables;
//
// Inner class
//
/**
* This class define a Python dictionary that __str__() returns can be
* defined.
*/
private static class PyStrDictionary extends PyDictionary {
private static final long serialVersionUID = 1L;
private PyString value;
/**
* The the value.
* @param value the value
*/
public void setValue(final String value) {
this.value = new PyString(value);
}
@Override
public PyString __str__() {
if (this.value != null) {
return this.value;
}
return super.__str__();
}
//
// Constructor
//
/**
* Default constructor.
*/
public PyStrDictionary() {
}
/**
* Constructor.
* @param value the value of the returns of __str___
*/
public PyStrDictionary(final String value) {
setValue(value);
}
}
/**
* Execute script by Python interpreter and replace variable name by value.
* @return final command line
* @throws EoulsanException if an error throws by interpretation.
*/
public String execute() throws EoulsanException {
try (final PythonInterpreter interpreter = new PythonInterpreter()) {
final PyObject nameSpace = createNameSpace(this.variables);
final String template = this.cheetahScript;
interpreter.set("template", template);
interpreter.set("nameSpace", nameSpace);
final String pythonScript = "from Cheetah.Template import Template\n"
+ "result = str(Template(template, searchList=[nameSpace]))";
interpreter.exec(pythonScript);
// Retrieve standard output
final PyObject cmd = interpreter.get("result");
return cmd.asString().replace('\n', ' ').trim();
}
}
/**
* Create the dictionary that contains all the placeholders for Cheetah.
* @param plateholders the placeholders
* @return a modified Python dictionnary
*/
private static PyStrDictionary createNameSpace(
final Map<String, String> plateholders) {
final PyStrDictionary result = new PyStrDictionary();
if (plateholders != null) {
for (Map.Entry<String, String> e : plateholders.entrySet()) {
List<String> fields = GuavaCompatibility.splitToList(Splitter.on('.'), e.getKey());
PyStrDictionary dict = result;
for (int i = 0; i < fields.size() - 1; i++) {
final String f = fields.get(i);
if (dict.containsKey(f)) {
Object o = dict.get(f);
if (o instanceof String) {
final PyStrDictionary newDict = new PyStrDictionary((String) o);
dict.put(f, newDict);
dict = newDict;
} else {
dict = (PyStrDictionary) dict.get(f);
}
} else {
final PyStrDictionary newDict = new PyStrDictionary();
dict.put(f, newDict);
dict = newDict;
}
}
final String key = fields.get(fields.size() - 1);
if (dict.containsKey(key)) {
((PyStrDictionary) dict.get(key)).setValue(e.getValue());
} else {
dict.put(key, e.getValue());
}
}
}
return result;
}
//
// Constructor
//
/**
* Instantiates a new tool Cheetah script interpreter.
* @param cheetahScript the Cheetah script to execute
* @param variables the variables of the script
* @throws EoulsanException if the constructor fails
*/
public CheetahInterpreter(final String cheetahScript,
final Map<String, String> variables) throws EoulsanException {
checkNotNull(variables, "No variable set for Cheetah interpreter");
checkState(!variables.isEmpty(),
"Tool instance from Galaxy Tool not found variables for interpretation");
this.cheetahScript = cheetahScript;
this.variables = new HashMap<>(variables);
}
}