package org.molgenis.generator;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.molgenis.compute.ComputeJob;
import org.molgenis.compute.ComputeParameter;
import org.molgenis.compute.ComputeProtocol;
import org.molgenis.gridhandler.CommandLineImputationGridHandler;
import org.molgenis.gridhandler.GridHandler;
import org.molgenis.pheno.ObservationTarget;
import org.molgenis.protocol.Workflow;
import org.molgenis.protocol.WorkflowElement;
import org.molgenis.util.Pair;
import org.molgenis.util.Tuple;
import java.io.*;
import java.util.*;
/**
* Created by IntelliJ IDEA.
* User: georgebyelas
* Date: 05/04/2012
* Time: 09:46
* To change this template use File | Settings | File Templates.
*/
//class with proper folding
public class Compute3JobGenerator implements JobGenerator
{
private static Logger logger = Logger.getLogger(Compute3JobGenerator.class);
//parsing/making folding story
private FoldingMaker foldingMaker = new FoldingMaker();
private FoldingParser foldingParser = new FoldingParser();
//to reuse few methods
ModelLoader loader = new ModelLoader();
//grid specific imputation handler
private GridHandler gridHandler = null;
private boolean workflowHasDependencies = false;
//template sources
private String templateGridHeader;
private String templateGridDownload;
private String templateGridDownloadExe;
private String templateGridUpload;
private String templateGridJDL;
private String templateGridAfterExecution;
private String templateGridUploadLog;
private String templateGridDAGNode;
private String templateMacro;
private String templateClusterSubmission;
private String templateClusterHeader;
private String templateClusterFooter;
//template filenames
private String fileTemplateGridHeader = "templ-grid-head.ftl";
private String fileTemplateGridDownload = "templ-download-grid.ftl";
private String fileTemplateGridDownloadExe = "templ-exe-grid.ftl";
private String fileTemplateGridUpload = "templ-upload-grid.ftl";
private String fileTemplateGridUploadLog = "templ-upload-grid-log.ftl";
private String fileTemplateGridJDL = "templ-jdl-grid.ftl";
private String fileTemplateGridAfterExecution = "templ-after-exe.ftl";
private String fileTemplateGridDAGNode = "templ-jdl-dag-node.ftl";
private String fileTemplateClusterHeader = "templ-pbs-header.ftl";
private String fileTemplateClusterFooter = "templ-pbs-footer.ftl";
private String fileTemplateClusterSubmission = "templ-submit.ftl";
private String fileTemplateMacro = "templ-macro.ftl";
//used for grid generation
private Hashtable<String, GridTransferContainer> pairJobTransfers = null;
//used for cluster generation - submit script
private Hashtable<WorkflowElement, ComputeJob> pairWEtoCJ = null;
private Hashtable<ComputeJob, WorkflowElement> pairCJtoWE = null;
//submission script for the cluster - filled when processing jobs for cluster
private String submitScript = null;
//dag file for submission for the grid
private String dagScript = null;
//dag dependencies list - filled when processing jobs for grid
private String dagDependencies = null;
private Hashtable<String, String> config;
private List<Tuple> worksheet = null;
public void setWorksheet(List<Tuple> worksheet)
{
this.worksheet = worksheet;
}
public Vector<ComputeJob> generateComputeJobsFoldedWorksheet(Workflow workflow, List<Tuple> f, String backend)
{
//create the table with targets, which is equal to worksheet if there are no targets
List<Hashtable> table = null;
//check if workflow elements have dependencies
workflowHasDependencies = hasDependencies(workflow);
//remove unused parameters from the worksheet
List<Hashtable> worksheet = foldingMaker.transformToTable(f);
foldingMaker.setWorkflow(workflow);
worksheet = foldingMaker.removeUnused(worksheet, (List<ComputeParameter>) workflow.getWorkflowComputeParameterCollection());
//result jobs
Vector<ComputeJob> computeJobs = new Vector<ComputeJob>();
//if (backend.equalsIgnoreCase(JobGenerator.GRID))
pairJobTransfers = new Hashtable<String, GridTransferContainer>();
pairWEtoCJ = new Hashtable<WorkflowElement, ComputeJob>();
pairCJtoWE = new Hashtable<ComputeJob, WorkflowElement>();
if (backend.equalsIgnoreCase(JobGenerator.CLUSTER))
{
submitScript = "";
}
else if (backend.equalsIgnoreCase(JobGenerator.GRID) && workflowHasDependencies)
{
dagScript = "Type=\"dag\";\n\n";
dagDependencies = "";
}
Collection<ComputeParameter> parameters = workflow.getWorkflowComputeParameterCollection();
Collection<WorkflowElement> workflowElements = workflow.getWorkflowWorkflowElementCollection();
for (WorkflowElement el : workflowElements)
{
ComputeProtocol protocol = (ComputeProtocol) el.getProtocol();
String template = protocol.getScriptTemplate();
//chack if we have any targets
List<ComputeParameter> targets = foldingMaker.findTargets(protocol.getScriptTemplate());
if (targets != null)
{
table = foldingMaker.fold(targets, worksheet);
}
else
table = worksheet;
//here, we prapare some information about folded table
//in particular, we find what parameters are Martijn's folded constants
foldingParser.evaluateTable(table);
//we set all parameters to foldered parser, which are used for reducing foldered constants
//this comment does give any clue to what is going on :)
foldingParser.setParametersList(parameters);
//now we start to use foldered worksheet
//all our parameters, that depend on foldered worksheet, will become lists as well, that upset me a lot :(
for (int i = 0; i < table.size(); i++)
{
//because Hashtable does not allow null keys or values used for weaving
Hashtable<String, Object> values = new Hashtable<String, Object>();
//parameters which are templates and do directly depend on worksheet values
Vector<ComputeParameter> complexParameters = new Vector<ComputeParameter>();
//hashtable with simple values, we need it for initial weaving
Hashtable<String, String> simpleValues = new Hashtable<String, String>();
//job naming
String id = "id";
Hashtable<String, Object> line = table.get(i);
if (targets != null)
{
//use targets to create name
Enumeration ekeys = line.keys();
while (ekeys.hasMoreElements())
{
String ekey = (String) ekeys.nextElement();
if (isTarget(ekey, targets))
{
Object eValues = line.get(ekey);
values.put(ekey, eValues);
String vvv = eValues.toString();
vvv = vvv.replaceAll(" ", "_");
id += "_" + vvv;
}
}
}
else
{
//use the whole line to create name
Enumeration ekeys = line.keys();
while (ekeys.hasMoreElements())
{
String ekey = (String) ekeys.nextElement();
Object eValues = line.get(ekey);
values.put(ekey, eValues);
String vvv = eValues.toString();
vvv = vvv.replaceAll(" ", "_");
id += "_" + vvv;
}
}
for (ComputeParameter parameter : parameters)
{
if (parameter.getDefaultValue() != null)
{
if (parameter.getDefaultValue().contains("${"))
{
complexParameters.addElement(parameter);
}
else
{
values.put(parameter.getName(), parameter.getDefaultValue());
simpleValues.put(parameter.getName(), parameter.getDefaultValue());
}
}
}
logger.log(Level.DEBUG, "simple parameters before: " + values.size());
//we transform complex parameters to unweaved values, because unweaved value can folded
Hashtable<String, Object> unweavedValues = new Hashtable<String, Object>();
for (ComputeParameter par : complexParameters)
{
Pair<String, Object> value = processDependentParameter(par, line, simpleValues);
if (foldingParser.isValueSimple(value))
{
values.put(par.getName(), value.getB());
}
else
{
unweavedValues.put(par.getName(), value.getB());
}
}
logger.log(Level.DEBUG, "simple parameters after " + values.size() + " parameters to weave: " + complexParameters.size());
Vector<String> vecToRemove = new Vector<String>();
int weavingCount = 0;
logger.log(Level.DEBUG, "loop " + weavingCount + " -> " + unweavedValues.size());
//in a loop weave complex parameters with values
while (unweavedValues.size() > 0 && weavingCount < 100)
{
Enumeration unkeys = unweavedValues.keys();
while (unkeys.hasMoreElements())
{
String unkey = (String) unkeys.nextElement();
Object eValue = unweavedValues.get(unkey);
Pair<String, Object> value = null;
if (eValue instanceof Collection<?>)
{
List<String> unweavedLines = (List<String>) eValue;
value = processUnweavedCollection(unkey, unweavedLines, values);
}
else
{
String unweavedLine = (String) eValue;
value = processUnweavedLine(unkey, unweavedLine, values, 0);
}
if (foldingParser.isValueSimple(value))
{
values.put(value.getA(), value.getB());
vecToRemove.add(unkey);
}
else
unweavedValues.put(value.getA(), value.getB());
}
for (String str : vecToRemove)
unweavedValues.remove(str);
weavingCount++;
logger.log(Level.DEBUG, "loop/parameters to weave " + weavingCount + " -> " + unweavedValues.size());
}
String jobListing = foldingMaker.weaveFreemarker(template, values);
ComputeJob job = new ComputeJob();
String jobName = config.get(JobGenerator.GENERATION_ID) + "_" +
workflow.getName() + "_" +
el.getName() + "_" + id;
job.setName(jobName);
job.setProtocol(protocol);
job.setComputeScript(jobListing);
computeJobs.add(job);
//fill containers for grid jobs to ensure correct data transfer
// and for cluster to generate submit script
//if (backend.equalsIgnoreCase(JobGenerator.GRID))
{
GridTransferContainer container = fillContainer(protocol, values);
pairJobTransfers.put(job.getName(), container);
}
//else if (backend.equalsIgnoreCase(JobGenerator.CLUSTER))
{
pairWEtoCJ.put(el, job);
pairCJtoWE.put(job, el);
}
logger.log(Level.DEBUG, "----------------------------------------------------------------------");
logger.log(Level.DEBUG, el.getName());
logger.log(Level.DEBUG, jobListing);
logger.log(Level.DEBUG, "----------------------------------------------------------------------");
}
}
return computeJobs;
}
private boolean hasDependencies(Workflow workflow)
{
Collection<WorkflowElement> workflowElements = workflow.getWorkflowWorkflowElementCollection();
for (WorkflowElement el : workflowElements)
{
if (el.getPreviousSteps().size() > 0)
return true;
}
return false;
}
private boolean isTarget(String ekey, List<ComputeParameter> targets)
{
for (ComputeParameter par : targets)
{
String name = par.getName();
if (name.equalsIgnoreCase(ekey))
return true;
}
return false;
}
private Pair<String, Object> processUnweavedLine(String unkey, String unweavedLine, Hashtable<String, Object> values, int i)
{
Pair<String, Object> pair = new Pair<String, Object>();
Hashtable<String, String> hashtable = prepareSimpleValues(values, i);
String value = foldingParser.doByHand(unweavedLine, hashtable);
pair.setA(unkey);
pair.setB(value);
return pair;
}
private Hashtable<String, String> prepareSimpleValues(Hashtable<String, Object> values, int i)
{
Hashtable<String, String> result = new Hashtable<String, String>();
Enumeration unkeys = values.keys();
while (unkeys.hasMoreElements())
{
String unkey = (String) unkeys.nextElement();
Object eValue = values.get(unkey);
String vvv;
if (eValue instanceof Collection<?>)
{
List<String> list = (List<String>) eValue;
vvv = list.get(i);
}
else
{
vvv = (String) eValue;
}
result.put(unkey, vvv);
}
return result;
}
private Pair<String, Object> processUnweavedCollection(String unkey, List<String> unweavedLines, Hashtable<String, Object> values)
{
Pair<String, Object> pair = new Pair<String, Object>();
List<String> list = new ArrayList<String>();
for (int i = 0; i < unweavedLines.size(); i++)
{
String input = unweavedLines.get(i);
Pair<String, Object> aPair = processUnweavedLine(unkey, input, values, i);
list.add((String) aPair.getB());
}
pair.setA(unkey);
pair.setB(list);
return pair;
}
//here, we also identify what parameters should be foldered
private Pair<String, Object> processDependentParameter
(ComputeParameter par, Hashtable<String, Object> line, Hashtable<String, String> simpleValues)
{
Pair<String, Object> pair = new Pair<String, Object>();
pair.setA(par.getName());
int lineFolderedSize = foldingParser.getFolderedLineSize(line);
String parTemplate = par.getDefaultValue();
foldingParser.setNotList();
foldingParser.checkIsList(parTemplate);
boolean isList = foldingParser.getIsList();
if (lineFolderedSize > 1 && isList)
{
List<String> values = new ArrayList<String>();
for (int i = 0; i < lineFolderedSize; i++)
{
String value = foldingParser.parseTemplateLineByHand(parTemplate, line, i, simpleValues);
values.add(value);
}
pair.setB(values);
}
else
{
String value = foldingParser.parseTemplateLineByHand(parTemplate, line, 0, simpleValues);
pair.setB(value);
}
return pair;
}
private GridTransferContainer fillContainer(ComputeProtocol protocol, Hashtable<String, Object> values)
{
GridTransferContainer container = new GridTransferContainer();
List<ComputeParameter> inputs = protocol.getInputs();
for (ComputeParameter input : inputs)
{
String name = input.getName();
String value = (String) values.get(name);
container.addInput(name, value);
}
List<ComputeParameter> outputs = protocol.getOutputs();
for (ComputeParameter output : outputs)
{
String name = output.getName();
String value = (String) values.get(name);
container.addOutput(name, value);
}
List<ComputeParameter> exes = protocol.getExes();
for (ComputeParameter exe : exes)
{
String name = exe.getName();
String value = (String) values.get(name);
container.addExe(name, value);
}
List<ComputeParameter> logs = protocol.getLogs();
for (ComputeParameter log : logs)
{
String name = log.getName();
String value = (String) values.get(name);
container.addLog(name, value);
}
return container;
}
public Vector<ComputeJob> generateComputeJobsDB(Workflow workflow, List<ObservationTarget> worksheet, String backend)
{
return null;
}
public boolean generateActualJobsWithMacros(Vector<ComputeJob> computeJobs, String backend, Hashtable<String, String> config)
{
//read templates
String templatesDir = config.get(JobGenerator.TEMPLATE_DIR);
readTemplates(templatesDir);
for (ComputeJob computeJob : computeJobs)
{
GridTransferContainer container = pairJobTransfers.get(computeJob.getName());
String strMacrosInput = makeMacros(container, computeJob.getComputeScript(), "input", backend);
String strMacrosOutput = makeMacros(container, computeJob.getComputeScript(), "output", backend);
System.out.println(">>> generation job: " + computeJob.getName());
if (backend.equalsIgnoreCase(JobGenerator.CLUSTER))
{
generateActualJobCluster(computeJob, config, strMacrosInput, strMacrosOutput);
}
else if (backend.equalsIgnoreCase(JobGenerator.GRID))
{
generateActualJobGridMacro(computeJob, config, strMacrosInput, strMacrosOutput);
}
}
//write cluster submit script
if (backend.equalsIgnoreCase(JobGenerator.CLUSTER))
writeToFile(config.get(JobGenerator.OUTPUT_DIR) + System.getProperty("file.separator") + "submit_" + config.get(JobGenerator.GENERATION_ID) + ".sh",
submitScript);
return true;
}
//here we create macros listing
private String makeMacros(GridTransferContainer container, String script, String type, String backend)
{
String text = "";
if (type.equalsIgnoreCase("input"))
{
text += JobGenerator.SOURCE_SCRIPT + "\n";
Vector<String> nameInputs = loader.findFlagValues(script, ModelLoader.FLAG_INPUTS);
Hashtable<String, String> inputs = container.getInputs();
for (String s : nameInputs)
{
String macroline = makeMacroLine(s, inputs, type, backend);
text += macroline;
}
Vector<String> nameExes = loader.findFlagValues(script, ModelLoader.FLAG_EXES);
Hashtable<String, String> exes = container.getExes();
for (String s : nameExes)
{
String macroline = makeMacroLine(s, exes, JobGenerator.EXE, backend);
text += macroline;
}
}
else if (type.equalsIgnoreCase("output"))
{
text += "\n";
Vector<String> nameOutputs = loader.findFlagValues(script, ModelLoader.FLAG_OUTPUTS);
Hashtable<String, String> outputs = container.getOutputs();
for (String s : nameOutputs)
{
String macroline = makeMacroLine(s, outputs, type, backend);
text += macroline;
}
}
return text;
}
private String makeMacroLine(String s, Hashtable<String, String> inputs, String type, String backend)
{
String macro = null;
if (s.contains(".*"))
{
String prefix = s.substring(0, s.lastIndexOf("."));
Enumeration keys = inputs.keys();
boolean isPathSet = false;
Hashtable<String, String> weaveValues = new Hashtable<String, String>();
String extensions = "";
while (keys.hasMoreElements())
{
String name = (String) keys.nextElement();
if (name.contains(prefix))
{
int prefixIndex = name.indexOf(prefix);
if (prefixIndex == 0)
{
String value = inputs.get(name);
//here we chack is it the path or this variable here by mistake of naming conventions
if (value.lastIndexOf("/") > -1)
{
//to set path and other variables only once
if (!isPathSet)
{
weaveValues.put(JobGenerator.MACRO_BACKEND, backend);
weaveValues.put(JobGenerator.MACRO_TYPE, type);
int lastSlash = value.lastIndexOf("/");
String path = value.substring(0, lastSlash + 1);
weaveValues.put(JobGenerator.MACRO_PATH, path);
String actualName = value.substring(lastSlash + 1, value.length());
int firstDot = actualName.indexOf(".");
String vvv = actualName.substring(0, firstDot);
weaveValues.put(JobGenerator.MACRO_NAME, vvv);
String extension = actualName.substring(firstDot, actualName.length());
extensions += " " + "\"" + extension + "\"";
isPathSet = true;
}
else
{
int lastSlash = value.lastIndexOf("/");
String actualName = value.substring(lastSlash + 1, value.length());
int firstDot = actualName.indexOf(".");
String extension = actualName.substring(firstDot, actualName.length());
extensions += " " + "\"" + extension + "\"";
}
}
}
}
}
weaveValues.put(JobGenerator.MACRO_EXTENSIONS, extensions);
macro = weaveFreemarker(templateMacro, weaveValues);
int z = 0;
}
else
{
Enumeration keys = inputs.keys();
while (keys.hasMoreElements())
{
String name = (String) keys.nextElement();
if (s.equalsIgnoreCase(name))
{
String value = inputs.get(name);
Hashtable<String, String> weaveValues = new Hashtable<String, String>();
weaveValues.put(JobGenerator.MACRO_BACKEND, backend);
weaveValues.put(JobGenerator.MACRO_TYPE, type);
int lastSlash = value.lastIndexOf("/");
String path = value.substring(0, lastSlash + 1);
weaveValues.put(JobGenerator.MACRO_PATH, path);
String actualName = value.substring(lastSlash + 1, value.length());
int firstDot = actualName.indexOf(".");
if (firstDot < 0)
{
String vvv = actualName.substring(0, actualName.length());
weaveValues.put(JobGenerator.MACRO_NAME, vvv);
weaveValues.put(JobGenerator.MACRO_EXTENSIONS, "");
}
else
{
String vvv = actualName.substring(0, firstDot);
weaveValues.put(JobGenerator.MACRO_NAME, vvv);
String extension = actualName.substring(firstDot, actualName.length());
extension = "\"" + extension + "\"";
weaveValues.put(JobGenerator.MACRO_EXTENSIONS, extension);
}
macro = weaveFreemarker(templateMacro, weaveValues);
}
}
}
return macro; //To change body of created methods use File | Settings | File Templates.
}
private void generateActualJobGridMacro(ComputeJob computeJob, Hashtable<String, String> config, String strMacrosInput, String strMacrosOutput)
{
Hashtable<String, String> values = new Hashtable<String, String>();
values.put("script_name", computeJob.getName());
values.put("error_log", "err_" + computeJob.getName() + ".log");
values.put("output_log", "out_" + computeJob.getName() + ".log");
values.put("script_location", config.get(JobGenerator.BACK_END_DIR));
values.put("node_name", computeJob.getName());
//create jdl
String jdlListing = weaveFreemarker(templateGridJDL, values);
//write jdl
(new File(config.get(JobGenerator.OUTPUT_DIR))).mkdirs();
writeToFile(config.get(JobGenerator.OUTPUT_DIR) + System.getProperty("file.separator") + computeJob.getName() + ".jdl",
jdlListing);
//create shell
String shellListing = templateGridHeader;
String initialScript = computeJob.getComputeScript();
GridTransferContainer container = pairJobTransfers.get(computeJob.getName());
//generate downloading section (transfer inputs and executable)
//and change job listing to execute in the grid
Hashtable<String, String> inputs = container.getInputs();
Enumeration actuals = inputs.elements();
while (actuals.hasMoreElements())
{
String actualName = (String) actuals.nextElement();
String justName = giveJustName(actualName);
//escapes are required to avoid $ sign processing in String replaceAll method
justName = "\\" + justName;
//commented out - but I keep it if I need to sho somebody the problem of replacement with wild cards
// System.out.println("actual " + actualName);
// System.out.println("just " + justName);
//
// System.out.println("------------- before");
// System.out.println(initialScript);
initialScript = initialScript.replaceAll(actualName, justName);
// System.out.println("------------- after");
// System.out.println(initialScript);
}
Hashtable<String, String> exes = container.getExes();
actuals = exes.elements();
while (actuals.hasMoreElements())
{
String actualName = (String) actuals.nextElement();
String justName = giveJustName(actualName);
justName = "\\" + justName;
initialScript = initialScript.replaceAll(actualName, justName);
}
shellListing += strMacrosInput;
shellListing += initialScript;
String outputsString = "";
Hashtable<String, String> outputs = container.getOutputs();
actuals = outputs.elements();
while (actuals.hasMoreElements())
{
String actualName = (String) actuals.nextElement();
String justName = giveJustName(actualName);
justName = "\\" + justName;
shellListing = shellListing.replaceAll(actualName, justName);
}
shellListing += strMacrosOutput;
//write shell
writeToFile(config.get(JobGenerator.OUTPUT_DIR) + System.getProperty("file.separator") + computeJob.getName() + ".sh",
shellListing);
}
public boolean generateActualJobs(Vector<ComputeJob> computeJobs, String backend, Hashtable<String, String> config)
{
int generationCount = -1;
//read templates
String templatesDir = config.get(JobGenerator.TEMPLATE_DIR);
if (backend.equalsIgnoreCase(JobGenerator.GRID))
{
readTemplatesGrid(templatesDir);
gridHandler = new CommandLineImputationGridHandler();
gridHandler.setWorksheet(worksheet);
generationCount = gridHandler.getNextJobID();
//adding dag dependencies
if (workflowHasDependencies)
{
dagScript += "nodes = [\n";
}
}
else if (backend.equalsIgnoreCase(JobGenerator.CLUSTER))
readTemplatesCluster(templatesDir);
for (ComputeJob computeJob : computeJobs)
{
System.out.println(">>> generation job: " + computeJob.getName());
//generate files for selected back-end
if (backend.equalsIgnoreCase(JobGenerator.GRID))
generateActualJobGrid(computeJob, config, generationCount);
else if (backend.equalsIgnoreCase(JobGenerator.CLUSTER))
generateActualJobCluster(computeJob, config);
generationCount++;
}
//write cluster submit script
if (backend.equalsIgnoreCase(JobGenerator.CLUSTER))
writeToFile(config.get(JobGenerator.OUTPUT_DIR) + System.getProperty("file.separator") + "submit_" + config.get(JobGenerator.GENERATION_ID) + ".sh",
submitScript);
else if (backend.equalsIgnoreCase(JobGenerator.GRID) && workflowHasDependencies)
{
//produce targetsListFile
gridHandler.writeJobsLogsToFile(config);
//finilize dag
dagScript += "\n];";
// cut last coma and new line
dagDependencies = dagDependencies.substring(0, dagDependencies.length() - 2);
dagDependencies = "\ndependencies = {\n" + dagDependencies + "\n}";
dagScript += dagDependencies;
//write dag file
writeToFile(config.get(JobGenerator.OUTPUT_DIR) + System.getProperty("file.separator") +
"dag_" + config.get(JobGenerator.GENERATION_ID) + ".jdl",
dagScript);
}
return true;
}
private void generateActualJobCluster(ComputeJob computeJob, Hashtable<String, String> config)
{
//create values hashtable to fill templates
Hashtable<String, String> values = new Hashtable<String, String>();
ComputeProtocol protocol = (ComputeProtocol) computeJob.getProtocol();
values.put(JobGenerator.JOB_ID, computeJob.getName());
values.put(ModelLoader.FLAG_CLUSTER_QUEUE, protocol.getClusterQueue());
values.put(ModelLoader.FLAG_CORES, protocol.getCores().toString());
values.put(ModelLoader.FLAG_NODES, protocol.getNodes().toString());
values.put(ModelLoader.FLAG_MEMORY, protocol.getMem());
values.put(ModelLoader.FLAG_WALLTIME, protocol.getWalltime());
//create actual cluster job
String header = weaveFreemarker(templateClusterHeader, values);
String main = computeJob.getComputeScript();
String footer = weaveFreemarker(templateClusterFooter, values);
String actualJob = header + main + footer;
//write script
(new File(config.get(JobGenerator.OUTPUT_DIR))).mkdirs();
writeToFile(config.get(JobGenerator.OUTPUT_DIR) + System.getProperty("file.separator") + computeJob.getName() + ".sh",
actualJob);
//create job submission part
WorkflowElement el = pairCJtoWE.get(computeJob);
if (el.getPreviousSteps().size() > 0)
{
String dependency = JobGenerator.DEPENDENCY_HEAD;
for (WorkflowElement wEl : el.getPreviousSteps())
{
ComputeJob cJ = pairWEtoCJ.get(wEl);
dependency += ":" + cJ.getName();
values.put(JobGenerator.JOB_DEPENDENCIES, dependency);
}
}
else
values.put(JobGenerator.JOB_DEPENDENCIES, "");
String strSubmit = weaveFreemarker(templateClusterSubmission, values);
submitScript += strSubmit;
}
private void generateActualJobCluster(ComputeJob computeJob, Hashtable<String, String> config, String macrosInput, String macrosOutput)
{
//create values hashtable to fill templates
Hashtable<String, String> values = new Hashtable<String, String>();
ComputeProtocol protocol = (ComputeProtocol) computeJob.getProtocol();
values.put(JobGenerator.JOB_ID, computeJob.getName());
values.put(ModelLoader.FLAG_CLUSTER_QUEUE, protocol.getClusterQueue());
values.put(ModelLoader.FLAG_CORES, protocol.getCores().toString());
values.put(ModelLoader.FLAG_NODES, protocol.getNodes().toString());
values.put(ModelLoader.FLAG_MEMORY, protocol.getMem());
values.put(ModelLoader.FLAG_WALLTIME, protocol.getWalltime());
//create actual cluster job
String header = weaveFreemarker(templateClusterHeader, values);
String main = computeJob.getComputeScript();
String footer = weaveFreemarker(templateClusterFooter, values);
String actualJob = header + macrosInput + main + macrosOutput + footer;
//write script
(new File(config.get(JobGenerator.OUTPUT_DIR))).mkdirs();
writeToFile(config.get(JobGenerator.OUTPUT_DIR) + System.getProperty("file.separator") + computeJob.getName() + ".sh",
actualJob);
//create job submission part
WorkflowElement el = pairCJtoWE.get(computeJob);
if (el.getPreviousSteps().size() > 0)
{
String dependency = JobGenerator.DEPENDENCY_HEAD;
for (WorkflowElement wEl : el.getPreviousSteps())
{
ComputeJob cJ = pairWEtoCJ.get(wEl);
dependency += ":" + cJ.getName();
values.put(JobGenerator.JOB_DEPENDENCIES, dependency);
}
}
else
values.put(JobGenerator.JOB_DEPENDENCIES, "");
String strSubmit = weaveFreemarker(templateClusterSubmission, values);
submitScript += strSubmit;
}
//todo: method contains few constants that should be moved to interface
private void generateActualJobGrid(ComputeJob computeJob, Hashtable<String, String> config, int generationCount)
{
//create values hashtable to fill templates
Hashtable<String, String> values = new Hashtable<String, String>();
values.put("script_name", computeJob.getName());
values.put("error_log", "err_" + computeJob.getName() + ".log");
values.put("output_log", "out_" + computeJob.getName() + ".log");
values.put("script_location", config.get(JobGenerator.BACK_END_DIR));
values.put("node_name", computeJob.getName());
//create jdl
String jdlListing = weaveFreemarker(templateGridJDL, values);
if (workflowHasDependencies)
{
String dagNodeListing = weaveFreemarker(templateGridDAGNode, values);
dagScript += dagNodeListing + "\n";
}
//write jdl
(new File(config.get(JobGenerator.OUTPUT_DIR))).mkdirs();
writeToFile(config.get(JobGenerator.OUTPUT_DIR) + System.getProperty("file.separator") + computeJob.getName() + ".jdl",
jdlListing);
//create shell
String shellListing = templateGridHeader;
String initialScript = computeJob.getComputeScript();
GridTransferContainer container = pairJobTransfers.get(computeJob.getName());
//get log filename
Hashtable<String, String> logs = container.getLogs();
Enumeration logValues = logs.elements();
String logName = (String) logValues.nextElement();
String justLogName = giveJustName(logName);
//set log name to computeJob, that will be used in grid handler
computeJob.setLogFile("lfn://grid/" + logName);
//generate downloading section (transfer inputs and executable)
//and change job listing to execute in the grid
Hashtable<String, String> inputs = container.getInputs();
Enumeration actuals = inputs.elements();
while (actuals.hasMoreElements())
{
Hashtable<String, String> local = new Hashtable<String, String>();
String actualName = (String) actuals.nextElement();
String justName = giveJustName(actualName);
local.put(JobGenerator.LFN_NAME, actualName);
local.put(JobGenerator.INPUT, justName);
local.put(JobGenerator.LOG, justLogName);
String inputListing = weaveFreemarker(templateGridDownload, local);
//escapes are required to avoid $ sign processing in String replaceAll method
justName = "\\" + justName;
initialScript = initialScript.replaceAll(actualName, justName);
shellListing += inputListing;
}
Hashtable<String, String> exes = container.getExes();
actuals = exes.elements();
while (actuals.hasMoreElements())
{
Hashtable<String, String> local = new Hashtable<String, String>();
String actualName = (String) actuals.nextElement();
String justName = giveJustName(actualName);
local.put(JobGenerator.LFN_NAME, actualName);
local.put(JobGenerator.INPUT, justName);
local.put(JobGenerator.LOG, justLogName);
String inputListing = weaveFreemarker(templateGridDownloadExe, local);
logger.log(Level.DEBUG, "-----------");
logger.log(Level.DEBUG, initialScript);
logger.log(Level.DEBUG, "act " + actualName);
logger.log(Level.DEBUG, "just " + justName);
justName = "\\" + justName;
initialScript = initialScript.replaceAll(actualName, justName);
shellListing += inputListing;
}
shellListing += initialScript;
//generate uploading section
//and change job listing to execute in the grid
String outputsString = "";
Hashtable<String, String> outputs = container.getOutputs();
actuals = outputs.elements();
while (actuals.hasMoreElements())
{
Hashtable<String, String> local = new Hashtable<String, String>();
String actualName = (String) actuals.nextElement();
String justName = giveJustName(actualName);
//set output file to compute job, that will be used in grid handler
computeJob.setOutputFile("lfn://grid/" + actualName);
local.put(JobGenerator.LFN_NAME, actualName);
local.put(JobGenerator.OUTPUT, justName);
local.put(JobGenerator.LOG, justLogName);
String outputListing = weaveFreemarker(templateGridUpload, local);
justName = "\\" + justName;
shellListing = shellListing.replaceAll(actualName, justName);
//shellListing += outputListing;
outputsString += outputListing;
}
shellListing += outputsString;
//add upload log
Hashtable<String, String> local = new Hashtable<String, String>();
local.put(JobGenerator.LFN_NAME, logName);
local.put(JobGenerator.OUTPUT, justLogName);
local.put(JobGenerator.LOG, justLogName);
String outputListing = weaveFreemarker(templateGridUploadLog, local);
shellListing += outputListing;
//write shell
writeToFile(config.get(JobGenerator.OUTPUT_DIR) + System.getProperty("file.separator") + computeJob.getName() + ".sh",
shellListing);
//and computeJob to grid handler
gridHandler.setComputeJob(computeJob);
//write job dependencies to DAG
WorkflowElement el = pairCJtoWE.get(computeJob);
if (el.getPreviousSteps().size() > 0)
{
String jobName = computeJob.getName();
Vector<String> dependencyNames = new Vector<String>();
for (WorkflowElement wEl : el.getPreviousSteps())
{
ComputeJob cJ = pairWEtoCJ.get(wEl);
String strDependencyName = cJ.getName();
dependencyNames.addElement(strDependencyName);
}
String strDependency = "";
//more than one previous element
if (dependencyNames.size() > 1)
{
for (String str : dependencyNames)
{
strDependency += str + ", ";
}
//cut last coma
strDependency = strDependency.substring(0, strDependency.length() - 2);
strDependency = "{ " + strDependency + " }";
}
//only one dependency element
else
{
strDependency = dependencyNames.elementAt(0);
}
// format string and add to DAg
String toAdd = "{ " + jobName + ", " + strDependency + " },\n";
dagDependencies = toAdd + dagDependencies;
}
}
private String giveJustName(String actualName)
{
int posSlash = actualName.lastIndexOf("/");
String justName = actualName.substring(posSlash + 1);
return JobGenerator.GRID_TEMP_DIR + System.getProperty("file.separator") + justName;
}
private void readTemplatesCluster(String templatesDir)
{
try
{
templateClusterHeader = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateClusterHeader);
templateClusterFooter = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateClusterFooter);
templateClusterSubmission = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateClusterSubmission);
}
catch (IOException e)
{
e.printStackTrace();
}
}
private void readTemplatesGrid(String templatesDir)
{
try
{
templateGridHeader = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridHeader);
templateGridDownload = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridDownload);
templateGridDownloadExe = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridDownloadExe);
templateGridUpload = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridUpload);
templateGridUploadLog = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridUploadLog);
templateGridJDL = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridJDL);
templateGridAfterExecution = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridAfterExecution);
templateGridDAGNode = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridDAGNode);
}
catch (IOException e)
{
e.printStackTrace();
}
}
private void readTemplates(String templatesDir)
{
try
{
templateClusterHeader = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateClusterHeader);
templateClusterFooter = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateClusterFooter);
templateClusterSubmission = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateClusterSubmission);
templateGridHeader = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridHeader);
templateGridDownload = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridDownload);
templateGridDownloadExe = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridDownloadExe);
templateGridUpload = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridUpload);
templateGridUploadLog = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridUploadLog);
templateGridJDL = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridJDL);
templateGridAfterExecution = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateGridAfterExecution);
templateMacro = getFileAsString(templatesDir + System.getProperty("file.separator") + fileTemplateMacro);
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void setConfig(Hashtable<String, String> config)
{
this.config = config;
}
public String weaveFreemarker(String strTemplate, Hashtable<String, String> values)
{
Configuration cfg = new Configuration();
Template t = null;
StringWriter out = new StringWriter();
try
{
t = new Template("name", new StringReader(strTemplate), cfg);
t.process(values, out);
}
catch (TemplateException e)
{
//e.printStackTrace();
}
catch (IOException e)
{
//e.printStackTrace();
}
return out.toString();
}
private final String getFileAsString(String filename) throws IOException
{
File file = new File(filename);
if (!file.exists())
{
logger.log(Level.ERROR, "template file " + filename + " does not exist");
System.exit(1);
}
final BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(file));
final byte[] bytes = new byte[(int) file.length()];
bis.read(bytes);
bis.close();
return new String(bytes);
}
public void writeToFile(String outfilename, String script)
{
try
{
BufferedWriter out = new BufferedWriter(new FileWriter(outfilename));
out.write(script);
out.close();
}
catch (IOException e)
{
}
}
}