package uk.ac.ox.zoo.seeg.abraid.mp.common.service.workflow.support.runrequest;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.log4j.Logger;
import uk.ac.ox.zoo.seeg.abraid.mp.common.config.ModellingConfiguration;
import uk.ac.ox.zoo.seeg.abraid.mp.common.domain.CovariateFile;
import uk.ac.ox.zoo.seeg.abraid.mp.common.domain.DiseaseGroup;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* A freemarker based ScriptGenerator to generate model run scripts based on a template file.
* Copyright (c) 2014 University of Oxford
*/
public class FreemarkerScriptGenerator implements ScriptGenerator {
private static final Logger LOGGER = Logger.getLogger(FreemarkerScriptGenerator.class);
private static final String LOG_APPLYING_FREEMARKER_SCRIPT_TEMPLATE = "Applying freemarker script template";
private static final String LOG_APPLYING_FREEMARKER_TEMPLATE_FAILED = "Applying freemarker script template failed!";
private static final String LOG_ADDING_SCRIPT_FILE_TO_WORKSPACE = "Adding script file to workspace at %s";
private static final String LOG_SCRIPT_FILE_ADDED_TO_WORKSPACE = "Script file added to workspace at %s";
private static final String SCRIPT_FILE_NAME = "modelRun.R";
private static final String TEMPLATE_FILE_NAME = "ModelRunTemplate.ftl";
private static final String ASCII = "US-ASCII";
/**
* Creates a model run script file in the working directory for the given configuration.
* @param modellingConfiguration The model run configuration.
* @param workingDirectory The directory in which the script should be created.
* @param diseaseGroup The disease group being modelled.
* @param covariates The covariate file to use in the model.
* @return The script file.
* @throws IOException Thrown in response to issues creating the script file.
*/
@Override
public File generateScript(ModellingConfiguration modellingConfiguration, File workingDirectory,
DiseaseGroup diseaseGroup, Collection<CovariateFile> covariates)
throws IOException {
LOGGER.info(String.format(LOG_ADDING_SCRIPT_FILE_TO_WORKSPACE, workingDirectory.toString()));
//Load template from source folder
Template template = loadTemplate();
// Build the data-model
Map<String, Object> data = buildDataModel(
modellingConfiguration, diseaseGroup.getId(), diseaseGroup.getModelMode(), covariates);
// File output
File scriptFile = applyTemplate(workingDirectory, template, data);
LOGGER.info(String.format(LOG_SCRIPT_FILE_ADDED_TO_WORKSPACE, workingDirectory.toString()));
return scriptFile;
}
private static File applyTemplate(File workingDirectory, Template template, Map<String, Object> data)
throws IOException {
File scriptFile = Paths.get(workingDirectory.getAbsolutePath(), SCRIPT_FILE_NAME).toFile();
Writer fileWriter = null;
try {
LOGGER.info(LOG_APPLYING_FREEMARKER_SCRIPT_TEMPLATE);
fileWriter = new OutputStreamWriter(new FileOutputStream(scriptFile), Charset.forName(ASCII).newEncoder());
template.process(data, fileWriter);
fileWriter.flush();
} catch (TemplateException e) {
LOGGER.warn(LOG_APPLYING_FREEMARKER_TEMPLATE_FAILED);
throw new IOException("Either could not read the template file or the file was invalid.", e);
} finally {
if (fileWriter != null) {
fileWriter.close();
}
}
return scriptFile;
}
private Template loadTemplate() throws IOException {
//Freemarker configuration object
Configuration config = new Configuration();
config.setClassForTemplateLoading(this.getClass(), "");
return config.getTemplate(TEMPLATE_FILE_NAME);
}
private static Map<String, Object> buildDataModel(ModellingConfiguration modellingConfiguration, int diseaseGroupId,
String mode, Collection<CovariateFile> covariates) {
Map<String, Object> data = new HashMap<>();
data.put("dry_run", modellingConfiguration.getDryRunFlag());
data.put("max_cpu", modellingConfiguration.getMaxCPUs());
data.put("verbose", modellingConfiguration.getVerboseFlag());
data.put("disease", diseaseGroupId);
data.put("mode", mode);
data.put("covariates", covariates);
return data;
}
}