package org.jactr.tools.itr.ortho.exec; /* * default logging */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Collection; import java.util.Map; import java.util.TreeMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jactr.core.utils.parameter.IParameterized; import org.jactr.tools.itr.ortho.ISliceAnalysis; import org.jactr.tools.itr.ortho.ISliceAnalyzer; /** * default slice analyzer that has a single parameter AnalysisScript which will * be executed when the analysis is requested. This allows aribitrary analysis * tools to be used. <br> * <br> * There are special variables that can be expanded on the command line: * ${parameters} will expand to a space separated list of key=value pairs for * the parameters manipulated. ${start} and ${stop} expand to the iteration * indexes for this slice. ${directories} expands to a space separated list of * the model execution directories (relative to the root working directory). * ${workingDir} expands to the location of the prefered working directory for * this particular analysis (typically: {root}/report/{sliceNumber}). <br> * <br> * This analyzer can also parse limited output from the analysis script. One * item per line, the analyzer looks for the following tokens:<br> * FIT: label key1 value1 key2 value2<br> * DETAIL: label workingDirRelativeFileLocation<br> * IMAGE: label workingDirRelativeFileLocation<br> * <br> * DETAIL: and IMAGE: allow you to return the label and location of images or * additional information files. FIT: allows you to return a label for the fit * of a specific metric, followed by the actual statistic names and values. It * also looks for a specific key of 'flag' and value 'true' or 'false', which it * uses to highlight the particular slice. * * @author harrison */ public class ExecAnalyzer implements ISliceAnalyzer, IParameterized { /** * Logger definition */ static private final transient Log LOGGER = LogFactory .getLog(ExecAnalyzer.class); static public final String SCRIPT = "AnalysisScript"; static public final String PARAMETERS_OPTION = "${parameters}"; static private final String ESC_PARAMETERS = "\\$\\{parameters\\}"; static public final String START_INDEX_OPTION = "${start}"; static private final String ESC_START = "\\$\\{start\\}"; static public final String STOP_INDEX_OPTION = "${stop}"; static private final String ESC_STOP = "\\$\\{stop\\}"; static public final String DIRECTORIES_OPTION = "${directories}"; static private final String ESC_DIRECTORIES = "\\$\\{directories\\}"; static public final String WORKING_DIRECTORY_OPTION = "${workingDir}"; static private final String ESC_WORKING = "\\$\\{workingDir\\}"; static public final String FIT_KEY = "FIT:"; static public final String DETAIL_KEY = "DETAIL:"; static public final String IMAGE_KEY = "IMAGE:"; private String _script; public ExecAnalyzer() { } public ExecAnalyzer(String script) { _script = script; } public Object analyze(ISliceAnalysis sliceAnalysis) { try { Process analysisProc = assembleProcess(sliceAnalysis, _script); int returnValue = analysisProc.waitFor(); if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Process returned %d", returnValue)); /* * parse output */ parseOutput(analysisProc.getInputStream(), sliceAnalysis); } catch (IOException e) { LOGGER.error("ExecAnalyzer.analyze threw IOException : ", e); } catch (InterruptedException e) { LOGGER.error("ExecAnalyzer.analyze threw InterruptedException : ", e); } return null; } private void parseOutput(InputStream inputStream, ISliceAnalysis analysis) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader( inputStream)); String line = null; while ((line = reader.readLine()) != null) try { line = line.trim(); if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Processing output:%s", line)); if (line.startsWith(FIT_KEY)) { String[] parts = line.split(" "); String label = parts[1]; boolean flag = false; Map<String, String> values = new TreeMap<String, String>(); for (int i = 2; i < parts.length - 1; i += 2) { values.put(parts[i], parts[i + 1]); if (parts[i].equals("flag")) flag = Boolean.parseBoolean(parts[i + 1]); } analysis.addFitStatistics(label, values, flag); } else if (line.startsWith(DETAIL_KEY)) { String[] parts = line.split(" "); analysis.addDetail(parts[1], parts[2]); } else if (line.startsWith(IMAGE_KEY)) { String[] parts = line.split(" "); analysis.addImage(parts[1], parts[2]); } } catch (Exception e) { LOGGER.error("Failed to process line: " + line, e); } } private Process assembleProcess(ISliceAnalysis analysis, String template) throws IOException { if (template.indexOf(PARAMETERS_OPTION) != -1) { StringBuilder sb = new StringBuilder(); for (Map.Entry<String, Object> entry : analysis.getSlice() .getParameterValues().entrySet()) sb.append(entry.getKey()).append("=").append(entry.getValue()).append( " "); template = template.replaceAll(ESC_PARAMETERS, sb.toString()); } if (template.indexOf(START_INDEX_OPTION) != -1) template = template.replaceAll(ESC_START, "" + analysis.getSlice().getFirstIteration()); if (template.indexOf(STOP_INDEX_OPTION) != -1) template = template.replaceAll(ESC_STOP, "" + analysis.getSlice().getLastIteration()); if (template.indexOf(DIRECTORIES_OPTION) != -1) { StringBuilder sb = new StringBuilder(); for (String dir : analysis.getSlice().getWorkingDirectories()) sb.append(dir).append(" "); template = template.replaceAll(ESC_DIRECTORIES, sb.toString()); } if (template.indexOf(WORKING_DIRECTORY_OPTION) != -1) template = template.replaceAll(ESC_WORKING, analysis .getWorkingDirectory()); if (LOGGER.isDebugEnabled()) LOGGER.debug(String.format("Invoking %s", template)); ProcessBuilder builder = new ProcessBuilder(template.split(" ")); builder.redirectErrorStream(true); return builder.start(); } public String getParameter(String key) { return null; } public Collection<String> getPossibleParameters() { return null; } public Collection<String> getSetableParameters() { return null; } public void setParameter(String key, String value) { if (SCRIPT.equalsIgnoreCase(key)) _script = value; } }