From: <mwl...@us...> - 2007-07-18 15:56:38
|
Revision: 424 http://svn.sourceforge.net/cishell/?rev=424&view=rev Author: mwlinnem Date: 2007-07-18 08:30:28 -0700 (Wed, 18 Jul 2007) Log Message: ----------- Refactor JythonRunnerAlgorithm into 3 seperate classes. Changed JythonRunner to use the out_data property to define each result data's type, instead of always using the class name. Cleaned some other stuff up. Modified Paths: -------------- trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonAlgorithmFactory.java trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonFileProperty.java trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonRunnerAlgorithm.java Added Paths: ----------- trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonInterpreterInitializer.java trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonResultFormatter.java Modified: trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonAlgorithmFactory.java =================================================================== --- trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonAlgorithmFactory.java 2007-07-18 15:20:54 UTC (rev 423) +++ trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonAlgorithmFactory.java 2007-07-18 15:30:28 UTC (rev 424) @@ -17,7 +17,6 @@ * */ -//TODO: cleanup public class JythonAlgorithmFactory implements AlgorithmFactory { private BundleContext myBundleContext; @@ -43,8 +42,6 @@ CIShellContext context) { return new JythonRunnerAlgorithm(data, parameters, context, properties, myBundle); - - } public MetaTypeProvider createParameters(Data[] data) { Modified: trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonFileProperty.java =================================================================== --- trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonFileProperty.java 2007-07-18 15:20:54 UTC (rev 423) +++ trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonFileProperty.java 2007-07-18 15:30:28 UTC (rev 424) @@ -3,13 +3,10 @@ public class JythonFileProperty { public static final String SCRIPT_PATH_KEY = "script_path"; - public static final String RESULT_PREFIX = - JythonRunnerAlgorithm.SCRIPT_RESULT_PREFIX; - public static final String ARGUMENT_PREFIX = - JythonRunnerAlgorithm.SCRIPT_ARGUMENT_PREFIX; + public static final String RESULT_PREFIX = "result"; + public static final String ARGUMENT_PREFIX = "arg"; public static final String LABEL_SUFFIX = ".label"; public static final String TYPE_SUFFIX = ".type"; public static final String PARENT_SUFFIX = ".parent"; - } Added: trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonInterpreterInitializer.java =================================================================== --- trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonInterpreterInitializer.java (rev 0) +++ trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonInterpreterInitializer.java 2007-07-18 15:30:28 UTC (rev 424) @@ -0,0 +1,96 @@ +package org.cishell.templates.jythonrunner; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Dictionary; +import java.util.Enumeration; + +import org.cishell.framework.data.Data; +import org.osgi.service.log.LogService; +import org.python.core.PyFile; +import org.python.core.PyJavaInstance; +import org.python.util.PythonInterpreter; + +/** + * + * @author mwlinnem + * + */ +public class JythonInterpreterInitializer { + + protected LogService logger; + + public JythonInterpreterInitializer(LogService logger) { + this.logger = logger; + } + + public PythonInterpreter initializeInterpreter(PythonInterpreter interp, + Data[] data, Dictionary parameters) { + interp = passUserProvidedArguments(interp, parameters); + interp = passCIShellProvidedArguments(interp, data); + interp = initializeLogging(interp); + return interp; + } + + protected PythonInterpreter passUserProvidedArguments( + PythonInterpreter interp, Dictionary parameters) { + + Enumeration enumer = parameters.keys(); + while (enumer.hasMoreElements()) { + String key = (String) enumer.nextElement(); + Object value = parameters.get(key); + String argName = key; + + interp = passArgument(value, argName, interp); + } + + return interp; + } + + protected PythonInterpreter passCIShellProvidedArguments( + PythonInterpreter interp, Data[] data) { + for (int ii = 0; ii < data.length; ii++) { + Data argData = data[ii]; + Object arg = argData.getData(); + String argName = JythonFileProperty.ARGUMENT_PREFIX + ii; + + interp = passArgument(arg, argName, interp); + } + + return interp; + } + + protected PythonInterpreter initializeLogging(PythonInterpreter interp) { + interp.setErr(System.err); + interp.setOut(System.out); + return interp; + } + + + + protected PythonInterpreter passArgument(Object arg, String argName, + PythonInterpreter interp) { + if (! (arg instanceof File)) { + interp.set(argName, + new PyJavaInstance(arg)); + } else { + try { + File fileArg = (File) arg; + InputStream fileStream = fileArg.toURL().openStream(); + interp.set(argName, + new PyFile(fileStream)); + } catch (IOException e) { + logger.log(LogService.LOG_ERROR, "Problem opening file" + + " provided as an argument to jython script.", e); + e.printStackTrace(); + } + } + + return interp; + } + + + + +} Added: trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonResultFormatter.java =================================================================== --- trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonResultFormatter.java (rev 0) +++ trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonResultFormatter.java 2007-07-18 15:30:28 UTC (rev 424) @@ -0,0 +1,218 @@ +package org.cishell.templates.jythonrunner; + +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.List; + +import org.cishell.framework.algorithm.AlgorithmProperty; +import org.cishell.framework.data.BasicData; +import org.cishell.framework.data.Data; +import org.cishell.framework.data.DataProperty; +import org.osgi.service.log.LogService; + +/** + * + * @author mwlinnem + * + */ +public class JythonResultFormatter { + + public static final String DEFAULT_LABEL_VALUE = "Data"; + + protected LogService logger; + + public JythonResultFormatter(LogService logger) { + this.logger = logger; + } + + public Data[] formatRawResults(List rawResults, Data[] inputData, + Dictionary properties) { + List dataResults; + + dataResults = convertToData(rawResults, properties); + dataResults = addMetaData(dataResults, inputData, + properties); + + Data[] resultsArray = convertToArray(dataResults); + return resultsArray; + } + + /** + * adds metadata obtained from the algorithm's .properties files + * that specify information about what the script returns. + * @param data a list of data objects, in the order + * they were returned. + * @param inputData the data passed from CIShell to this algorithm + * @param properties information about the script, such as + * the labels, types, and parents of all the returned data. + * @return a list of data objects in the order they were provided, + * now containing the appropriate metadata obtained from the + * .properties file. + */ + protected List addMetaData(List data, Data[] inputData, Dictionary properties) { + List results = new ArrayList(); + for (int ii = 0; ii < data.size(); ii++) { + Data result = ((Data) data.get(ii)); + Dictionary metadataHolder = result.getMetaData(); + + String dataLabel = getResultLabel(properties, ii); + metadataHolder.put(DataProperty.LABEL, dataLabel); + + String dataType = getResultType(properties, ii); + metadataHolder.put(DataProperty.TYPE, dataType); + + Data dataParent = getResultParent(properties, ii, inputData); + if (dataParent != null) { + metadataHolder.put(DataProperty.PARENT, dataParent); + } //it's okay to not have a parent, little Timmy. + + results.add(result); + } + return results; + } + + protected String getResultLabel(Dictionary props, int numResult) { + String labelKey = JythonFileProperty.RESULT_PREFIX + numResult + + JythonFileProperty.LABEL_SUFFIX; + Object labelValue = props.get(labelKey); + + String labelValueString; + if (!(labelValue == null)) { + labelValueString = (String) labelValue; + } else { + labelValueString = DEFAULT_LABEL_VALUE; + logger.log(LogService.LOG_WARNING, "Label of data returned from " + + "jython script not specified in .properties file. " + + "Assigning label to '" + labelValueString + "'."); + } + return labelValueString; + } + + protected String getResultType(Dictionary props, int numResult) { + String typeKey = JythonFileProperty.RESULT_PREFIX + + numResult + JythonFileProperty.TYPE_SUFFIX; + Object typeValue = props.get(typeKey); + + String typeValueString; + if (! (typeValue == null)) { + typeValueString = (String) typeValue; + checkType(typeValueString); + + } else { + typeValueString = DataProperty.OTHER_TYPE; + logger.log(LogService.LOG_WARNING, "Type of data returned from " + + "jython script not specified in .properties file. " + + "Assigning type to '" + typeValueString + "'."); + } + return typeValueString; + } + + /** + * Looks to see whether the result has a parent specified in the + * algorithm's .properties file. If it does, return the parent data. + * Otherwise return null. + * @param props information about the script, such as + * the labels, types, and parents of all the returned data. + * @param numResult specifies which result's information we need to look + * up + * @param inputData the data CIShell passed this algorithm. + * @return either the parent of the result data specified by numResults, + * or null, if there is no parent specified. + */ + protected Data getResultParent(Dictionary props, int numResult, Data[] inputData) { + String childKey = JythonFileProperty.RESULT_PREFIX + numResult + + JythonFileProperty.PARENT_SUFFIX; + Object parentName = props.get(childKey); + + Data parent; + if (! (parentName == null)) { + //TODO: more validation on parentName + char parentDataIndexChar = getLastChar((String) parentName); + int parentDataIndex = Character.digit(parentDataIndexChar, 10); + if (parentDataIndex < inputData.length) { + parent = inputData[parentDataIndex]; + } else { + logger.log(LogService.LOG_WARNING, ".properties file " + + "tried to assign result" + numResult + "the " + + "parent arg"+ parentDataIndex + ", which has an " + + "index greater than any arg provided. Cannot " + + "assign result" + numResult + " a parent."); + parent = null; + } + } else { + //it's okay not to specify a parent. + parent = null; + } + return parent; + } + + /** + * Takes java objects and wraps them in our CIShell data objects + * so that they can be returned from the algorithm. + * @param rawResults a list of java objects. + * @return a list of data objects. + */ + protected List convertToData(List rawResults, Dictionary props) { + List results = new ArrayList(); + String outData = (String) props.get(AlgorithmProperty.OUT_DATA); + + if (outData.trim().equalsIgnoreCase(AlgorithmProperty.NULL_DATA)) { + return results; + } + + String[] formats = outData.split(","); + + int numFinalResults; + if (formats.length > rawResults.size()) { + numFinalResults = rawResults.size(); + logger.log(LogService.LOG_WARNING, "More out_data formats " + + "provided than an actual data returned. Ignoring extra " + + "formats."); + } else if (rawResults.size() > formats.length) { + numFinalResults = formats.length; + logger.log(LogService.LOG_WARNING, "More data returned than " + + "out_data formats provided. Ignoring additional data " + + "returned"); + } else { + //both are the same length. + numFinalResults = rawResults.size(); + } + + for (int ii = 0; ii < numFinalResults; ii++) { + Object rawResult = rawResults.get(ii); + BasicData data = new BasicData(rawResult, formats[ii]); + results.add(data); + } + return results; + } + + protected char getLastChar(String s) { + if (s.length() > 0) { + return s.charAt(s.length() - 1); + } else { + throw new IndexOutOfBoundsException("Cannot get the last " + + "character of an empy string"); + } + } + + protected Data[] convertToArray(List dataList) { + Data[] dataArray = new Data[dataList.size()]; + for (int ii = 0; ii < dataArray.length; ii++) { + dataArray[ii] = (Data) dataList.get(ii); + } + return dataArray; + } + + protected void checkType(String ts) { + if (! (ts.equals(DataProperty.MATRIX_TYPE) || + ts.equals(DataProperty.NETWORK_TYPE) || + ts.equals(DataProperty.TEXT_TYPE) || + ts.equals(DataProperty.OTHER_TYPE))) { + logger.log(LogService.LOG_WARNING, "JythonRunnerAlgorithm: " + + "Assigning return data an unsupported data type " + + ts +". Either the type is invalid or " + + "JythonRunnerAlgorithm has not be updated to reflect " + + "types introduced in newer versions"); + } + } +} Modified: trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonRunnerAlgorithm.java =================================================================== --- trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonRunnerAlgorithm.java 2007-07-18 15:20:54 UTC (rev 423) +++ trunk/templates/org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonRunnerAlgorithm.java 2007-07-18 15:30:28 UTC (rev 424) @@ -1,23 +1,16 @@ package org.cishell.templates.jythonrunner; -import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Dictionary; -import java.util.Enumeration; import java.util.List; import org.cishell.framework.CIShellContext; import org.cishell.framework.algorithm.Algorithm; -import org.cishell.framework.data.BasicData; import org.cishell.framework.data.Data; -import org.cishell.framework.data.DataProperty; import org.osgi.framework.Bundle; import org.osgi.service.log.LogService; -import org.python.core.PyFile; -import org.python.core.PyJavaInstance; import org.python.core.PyObject; import org.python.util.PythonInterpreter; @@ -27,9 +20,6 @@ * */ -//TODO:refactor me into multiple classes -//TODO:general cleanup, renaming, etc... - public class JythonRunnerAlgorithm implements Algorithm { private Data[] data; private Dictionary parameters; @@ -38,10 +28,10 @@ private LogService logger; private URL script; + + private JythonInterpreterInitializer interpInitializer; + private JythonResultFormatter resultFormatter; - public static final String SCRIPT_ARGUMENT_PREFIX = "arg"; - public static final String SCRIPT_RESULT_PREFIX = "result"; - public JythonRunnerAlgorithm(Data[] data, Dictionary parameters, CIShellContext context, Dictionary properties, Bundle myBundle) { this.data = data; @@ -54,29 +44,24 @@ this.logger = (LogService) context.getService( LogService.class.getName()); + + this.interpInitializer = new JythonInterpreterInitializer(logger); + this.resultFormatter = new JythonResultFormatter(logger); } public Data[] execute() { - PythonInterpreter interp = initializeInterpreter( + PythonInterpreter interp = interpInitializer.initializeInterpreter( new PythonInterpreter(), data, parameters); List rawResults = runScript(interp, script); - Data[] results = formatRawResults(rawResults, data, properties); + Data[] results = resultFormatter.formatRawResults(rawResults, + data, properties); return results; } - - private PythonInterpreter initializeInterpreter(PythonInterpreter interp, - Data[] data, Dictionary parameters) { - interp = passUserProvidedArguments(interp, parameters); - interp = passCIShellProvidedArguments(interp, data); - interp = initializeLogging(interp); - return interp; - } - /** * Executes the script and extracts the raw results. * @param interp The initialized python interpreter @@ -89,17 +74,6 @@ return rawResults; } - private Data[] formatRawResults(List rawResults, Data[] inputData, - Dictionary properties) { - List dataResults = convertToData(rawResults); - List dataResultsWithMetaData = addMetaData(dataResults, inputData, - properties); - Data[] resultsArray = convertToArray(dataResultsWithMetaData); - return resultsArray; - } - - - private PythonInterpreter executeFile(PythonInterpreter interp, URL script) { try { @@ -112,40 +86,6 @@ return interp; } - private PythonInterpreter passUserProvidedArguments( - PythonInterpreter interp, Dictionary parameters) { - - Enumeration enumer = parameters.keys(); - while (enumer.hasMoreElements()) { - String key = (String) enumer.nextElement(); - Object value = parameters.get(key); - String argName = key; - - interp = passArgument(value, argName, interp); - } - - return interp; - } - - private PythonInterpreter passCIShellProvidedArguments( - PythonInterpreter interp, Data[] data) { - for (int ii = 0; ii < this.data.length; ii++) { - Data argData = this.data[ii]; - Object arg = argData.getData(); - String argName = SCRIPT_ARGUMENT_PREFIX + String.valueOf(ii); - - interp = passArgument(arg, argName, interp); - } - - return interp; - } - - private PythonInterpreter initializeLogging(PythonInterpreter interp) { - interp.setErr(System.err); - interp.setOut(System.out); - return interp; - } - /** * Gets Java versions of all the results from the script. * @param interp a python interpreter that holds results (presumably @@ -153,7 +93,7 @@ * @return A list of objects, where each object is a result from * the interpreters environment. */ - private List getRawResults(PythonInterpreter interp) { + protected List getRawResults(PythonInterpreter interp) { List results = new ArrayList(); /* @@ -162,207 +102,31 @@ * variable which is not defined. */ int ii = 0; - String resultName = SCRIPT_RESULT_PREFIX + ii; + String resultName = JythonFileProperty.RESULT_PREFIX + ii; while (variableIsDefined(interp, resultName)) { results.add(interp.get(resultName, Object.class)); ii++; - resultName = SCRIPT_RESULT_PREFIX + ii; + resultName = JythonFileProperty.RESULT_PREFIX + ii; } return results; } - /** - * adds metadata obtained from the algorithm's .properties files - * that specify information about what the script returns. - * @param data a list of data objects, in the order - * they were returned. - * @param inputData the data passed from CIShell to this algorithm - * @param properties information about the script, such as - * the labels, types, and parents of all the returned data. - * @return a list of data objects in the order they were provided, - * now containing the appropriate metadata obtained from the - * .properties file. - */ - private List addMetaData(List data, Data[] inputData, Dictionary properties) { - List results = new ArrayList(); - for (int ii = 0; ii < data.size(); ii++) { - Data result = ((Data) data.get(ii)); - Dictionary metadataHolder = result.getMetaData(); - - String dataLabel = getResultLabel(properties, ii); - metadataHolder.put(DataProperty.LABEL, dataLabel); - - String dataType = getResultType(properties, ii); - metadataHolder.put(DataProperty.TYPE, dataType); - - Data dataParent = getResultParent(properties, ii, inputData); - if (dataParent != null) { - metadataHolder.put(DataProperty.PARENT, dataParent); - } //it's okay to not have a parent, little Timmy. - - results.add(result); - } - return results; - } - - public String getResultLabel(Dictionary props, int numResult) { - String labelKey = JythonFileProperty.RESULT_PREFIX + numResult - + JythonFileProperty.LABEL_SUFFIX; - Object labelValue = props.get(labelKey); - - String labelValueString; - if (!(labelValue == null)) { - labelValueString = (String) labelValue; - } else { - labelValueString = "Data"; - logger.log(LogService.LOG_WARNING, "Label of data returned from " - + "jython script not specified in .properties file. " - + "Assigning label to '" + labelValueString + "'."); - } - return labelValueString; - } - - public String getResultType(Dictionary props, int numResult) { - String typeKey = JythonFileProperty.RESULT_PREFIX + - numResult + JythonFileProperty.TYPE_SUFFIX; - Object typeValue = props.get(typeKey); - - String typeValueString; - if (! (typeValue == null)) { - typeValueString = (String) typeValue; - checkType(typeValueString); - - } else { - typeValueString = DataProperty.OTHER_TYPE; - logger.log(LogService.LOG_WARNING, "Type of data returned from " + - "jython script not specified in .properties file. " + - "Assigning type to '" + typeValueString + "'."); - } - return typeValueString; - } - - /** - * Looks to see whether the result has a parent specified in the - * algorithm's .properties file. If it does, return the parent data. - * Otherwise return null. - * @param props information about the script, such as - * the labels, types, and parents of all the returned data. - * @param numResult specifies which result's information we need to look - * up - * @param inputData the data CIShell passed this algorithm. - * @return either the parent of the result data specified by numResults, - * or null, if there is no parent specified. - */ - public Data getResultParent(Dictionary props, int numResult, Data[] inputData) { - String childKey = JythonFileProperty.RESULT_PREFIX + numResult - + JythonFileProperty.PARENT_SUFFIX; - Object parentName = props.get(childKey); - - Data parent; - if (! (parentName == null)) { - //TODO: more validation on parentName - char parentDataIndexChar = getLastChar((String) parentName); - int parentDataIndex = Character.digit(parentDataIndexChar, 10); - if (parentDataIndex < inputData.length) { - parent = inputData[parentDataIndex]; - } else { - logger.log(LogService.LOG_WARNING, ".properties file " + - "tried to assign result" + numResult + "the " + - "parent arg"+ parentDataIndex + ", which has an " + - "index greater than any arg provided. Cannot " + - "assign result" + numResult + " a parent."); - parent = null; - } - } else { - //it's okay not to specify a parent. - parent = null; - } - return parent; - } - - private PythonInterpreter passArgument(Object arg, String argName, - PythonInterpreter interp) { - if (! (arg instanceof File)) { - interp.set(argName, - new PyJavaInstance(arg)); - } else { - try { - File fileArg = (File) arg; - InputStream fileStream = fileArg.toURL().openStream(); - interp.set(argName, - new PyFile(fileStream)); - } catch (IOException e) { - logger.log(LogService.LOG_ERROR, "Problem opening file" + - " provided as an argument to jython script.", e); - e.printStackTrace(); - } - } - - return interp; - } - - /** - * Takes java objects and wraps them in our CIShell data objects - * so that they can be returned from the algorithm. - * @param rawResults a list of java objects. - * @return a list of data objects. - */ - private List convertToData(List rawResults) { - List results = new ArrayList(); - for (int ii = 0; ii < rawResults.size(); ii++) { - Object rawResult = rawResults.get(ii); - String resultClassName = rawResult.getClass().getName(); - BasicData data = new BasicData(rawResult, resultClassName); - results.add(data); - } - return results; - } - private boolean variableIsDefined(PythonInterpreter interp, + protected boolean variableIsDefined(PythonInterpreter interp, String variableName) { String predicate = "vars().has_key('" + variableName + "') or " + "globals().has_key('" + variableName + "')"; boolean result = evalPredicate(interp, predicate); return result; } - private boolean evalPredicate(PythonInterpreter interp, String predicate) { + + protected boolean evalPredicate(PythonInterpreter interp, String predicate) { PyObject pyResult = interp.eval(predicate); Boolean resultObj = (Boolean) pyResult.__tojava__(Boolean.class); boolean result = resultObj.booleanValue(); return result; } - - private Data[] convertToArray(List dataList) { - Data[] dataArray = new Data[dataList.size()]; - for (int ii = 0; ii < dataArray.length; ii++) { - dataArray[ii] = (Data) dataList.get(ii); - } - return dataArray; - } - - private void checkType(String ts) { - if (! (ts.equals(DataProperty.MATRIX_TYPE) || - ts.equals(DataProperty.NETWORK_TYPE) || - ts.equals(DataProperty.TEXT_TYPE) || - ts.equals(DataProperty.OTHER_TYPE) || - ts.equals(DataProperty.TEXT_TYPE))) { - logger.log(LogService.LOG_WARNING, "JythonRunnerAlgorithm: " + - "Assigning return data an unsupported data type " + - ts +". Either the type is invalid or " + - "JythonRunnerAlgorithm has not be updated to reflect " + - "types introduced in newer versions"); - } - } - - public char getLastChar(String s) { - if (s.length() > 0) { - return s.charAt(s.length() - 1); - } else { - throw new IndexOutOfBoundsException("Cannot get the last " + - "character of an empy string"); - } - } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |