|
From: <mwl...@us...> - 2007-07-13 21:06:45
|
Revision: 418
http://svn.sourceforge.net/cishell/?rev=418&view=rev
Author: mwlinnem
Date: 2007-07-13 14:06:42 -0700 (Fri, 13 Jul 2007)
Log Message:
-----------
Initial import. JythonRunner allows CIShell to support jython algorithms.
Added Paths:
-----------
org.cishell.templates.jythonrunner/META-INF/
org.cishell.templates.jythonrunner/META-INF/MANIFEST.MF
org.cishell.templates.jythonrunner/OSGI-INF/
org.cishell.templates.jythonrunner/OSGI-INF/algorithm.properties
org.cishell.templates.jythonrunner/OSGI-INF/component.xml
org.cishell.templates.jythonrunner/OSGI-INF/l10n/
org.cishell.templates.jythonrunner/OSGI-INF/l10n/bundle_en.properties
org.cishell.templates.jythonrunner/OSGI-INF/metatype/
org.cishell.templates.jythonrunner/OSGI-INF/metatype/METADATA.XML
org.cishell.templates.jythonrunner/build.properties
org.cishell.templates.jythonrunner/src/
org.cishell.templates.jythonrunner/src/org/
org.cishell.templates.jythonrunner/src/org/cishell/
org.cishell.templates.jythonrunner/src/org/cishell/templates/
org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/
org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonAlgorithmFactory.java
org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonFileProperty.java
org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonRunnerAlgorithm.java
Added: org.cishell.templates.jythonrunner/META-INF/MANIFEST.MF
===================================================================
--- org.cishell.templates.jythonrunner/META-INF/MANIFEST.MF (rev 0)
+++ org.cishell.templates.jythonrunner/META-INF/MANIFEST.MF 2007-07-13 21:06:42 UTC (rev 418)
@@ -0,0 +1,25 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: JythonRunner
+Bundle-SymbolicName: org.cishell.templates.jythonrunner
+Bundle-Version: 0.0.1
+Bundle-ClassPath: .
+Bundle-Localization: plugin
+Import-Package: org.cishell.framework,
+ org.cishell.framework.algorithm,
+ org.cishell.framework.data,
+ org.osgi.framework;version="1.3.0",
+ org.osgi.service.component;version="1.0.0",
+ org.osgi.service.log;version="1.3.0",
+ org.osgi.service.metatype;version="1.1.0",
+ org.osgi.service.prefs;version="1.1.0",
+ org.python.compiler,
+ org.python.core,
+ org.python.modules,
+ org.python.modules.sre,
+ org.python.parser,
+ org.python.rmi,
+ org.python.util
+Export-Package: org.cishell.templates.jythonrunner
+X-AutoStart: true
+Service-Component: OSGI-INF/component.xml
Added: org.cishell.templates.jythonrunner/OSGI-INF/algorithm.properties
===================================================================
--- org.cishell.templates.jythonrunner/OSGI-INF/algorithm.properties (rev 0)
+++ org.cishell.templates.jythonrunner/OSGI-INF/algorithm.properties 2007-07-13 21:06:42 UTC (rev 418)
@@ -0,0 +1,6 @@
+label=Jython Script Runner
+description=Runs Jython Algorithms
+in_data=null
+out_data=null
+service.pid=edu.iu.nwb.converter.JythonRunnerAlgorithm
+remoteable=true
Added: org.cishell.templates.jythonrunner/OSGI-INF/component.xml
===================================================================
--- org.cishell.templates.jythonrunner/OSGI-INF/component.xml (rev 0)
+++ org.cishell.templates.jythonrunner/OSGI-INF/component.xml 2007-07-13 21:06:42 UTC (rev 418)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component name="org.cishell.templates.jythonrunner.component" immediate="false">
+ <implementation class="org.cishell.templates.jythonrunner.JythonAlgorithmFactory"/>
+ <properties entry="OSGI-INF/algorithm.properties"/>
+ <reference name="LOG" interface="org.osgi.service.log.LogService"/>
+ <reference name="MTS" interface="org.osgi.service.metatype.MetaTypeService"/>
+
+ <service>
+ <provide interface=
+ "org.cishell.framework.algorithm.AlgorithmFactory"/>
+ </service>
+</component>
\ No newline at end of file
Added: org.cishell.templates.jythonrunner/OSGI-INF/l10n/bundle_en.properties
===================================================================
--- org.cishell.templates.jythonrunner/OSGI-INF/l10n/bundle_en.properties (rev 0)
+++ org.cishell.templates.jythonrunner/OSGI-INF/l10n/bundle_en.properties 2007-07-13 21:06:42 UTC (rev 418)
@@ -0,0 +1,7 @@
+#Localization variables for OSGI-INF/metatatype/METADATA.XML
+#
+#Samples:
+#input=Input
+#desc=Enter an integer (that will be converted to a string)
+#name=Input->String
+#name_desc=Converts inputted integer to string
Added: org.cishell.templates.jythonrunner/OSGI-INF/metatype/METADATA.XML
===================================================================
--- org.cishell.templates.jythonrunner/OSGI-INF/metatype/METADATA.XML (rev 0)
+++ org.cishell.templates.jythonrunner/OSGI-INF/metatype/METADATA.XML 2007-07-13 21:06:42 UTC (rev 418)
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metatype:MetaData xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0">
+ <OCD name="My Algorithm" id="org.my.algorithm.MyAlgorithm.OCD"
+ description="">
+ </OCD>
+ <Designate pid="org.my.algorithm.MyAlgorithm">
+ <Object ocdref="org.my.algorithm.MyAlgorithm.OCD" />
+ </Designate>
+</metatype:MetaData>
Added: org.cishell.templates.jythonrunner/build.properties
===================================================================
--- org.cishell.templates.jythonrunner/build.properties (rev 0)
+++ org.cishell.templates.jythonrunner/build.properties 2007-07-13 21:06:42 UTC (rev 418)
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = build/
+bin.includes = META-INF/,\
+ .,\
+ OSGI-INF/
+jars.compile.order = .
Added: org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonAlgorithmFactory.java
===================================================================
--- org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonAlgorithmFactory.java (rev 0)
+++ org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonAlgorithmFactory.java 2007-07-13 21:06:42 UTC (rev 418)
@@ -0,0 +1,53 @@
+package org.cishell.templates.jythonrunner;
+
+import java.util.Dictionary;
+
+import org.cishell.framework.CIShellContext;
+import org.cishell.framework.algorithm.Algorithm;
+import org.cishell.framework.algorithm.AlgorithmFactory;
+import org.cishell.framework.data.Data;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.metatype.MetaTypeProvider;
+import org.osgi.service.metatype.MetaTypeService;
+/**
+ *
+ * @author mwlinnem
+ *
+ */
+
+//TODO: cleanup
+
+public class JythonAlgorithmFactory implements AlgorithmFactory {
+ private BundleContext myBundleContext;
+ private Bundle myBundle;
+ private MetaTypeProvider provider;
+ private Dictionary properties;
+
+ protected void activate(ComponentContext ctxt) {
+
+ MetaTypeService mts = (MetaTypeService)ctxt.locateService("MTS");
+ this.myBundleContext = ctxt.getBundleContext();
+ this.myBundle = myBundleContext.getBundle();
+ this.provider = mts.getMetaTypeInformation(myBundle);
+ this.properties = ctxt.getProperties();
+ }
+
+
+ protected void deactivate(ComponentContext ctxt) {
+ provider = null;
+ }
+
+ public Algorithm createAlgorithm(Data[] data, Dictionary parameters,
+ CIShellContext context) {
+ return new JythonRunnerAlgorithm(data, parameters, context,
+ properties, myBundle);
+
+
+ }
+
+ public MetaTypeProvider createParameters(Data[] data) {
+ return provider;
+ }
+}
\ No newline at end of file
Added: org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonFileProperty.java
===================================================================
--- org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonFileProperty.java (rev 0)
+++ org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonFileProperty.java 2007-07-13 21:06:42 UTC (rev 418)
@@ -0,0 +1,15 @@
+package org.cishell.templates.jythonrunner;
+
+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 LABEL_SUFFIX = ".label";
+ public static final String TYPE_SUFFIX = ".type";
+ public static final String PARENT_SUFFIX = ".parent";
+
+}
Added: org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonRunnerAlgorithm.java
===================================================================
--- org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonRunnerAlgorithm.java (rev 0)
+++ org.cishell.templates.jythonrunner/src/org/cishell/templates/jythonrunner/JythonRunnerAlgorithm.java 2007-07-13 21:06:42 UTC (rev 418)
@@ -0,0 +1,368 @@
+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;
+
+/**
+ *
+ * @author mwlinnem
+ *
+ */
+
+//TODO:refactor me into multiple classes
+//TODO:general cleanup, renaming, etc...
+
+public class JythonRunnerAlgorithm implements Algorithm {
+ private Data[] data;
+ private Dictionary parameters;
+ private Dictionary properties;
+
+ private LogService logger;
+
+ private URL script;
+
+ 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;
+ this.parameters = parameters;
+ this.properties = properties;
+
+ String scriptPath = (String) properties.get(
+ JythonFileProperty.SCRIPT_PATH_KEY);
+ script = myBundle.getResource(scriptPath);
+
+ this.logger = (LogService) context.getService(
+ LogService.class.getName());
+ }
+
+ public Data[] execute() {
+
+ PythonInterpreter interp = initializeInterpreter(
+ new PythonInterpreter(), data, parameters);
+
+ List rawResults = runScript(interp, script);
+
+ Data[] results = 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
+ * @param script The jython script itself, which the interpreter will run
+ * @return A list of objects that the script returned.
+ */
+ private List runScript(PythonInterpreter interp, URL script) {
+ interp = executeFile(interp, script);
+ List rawResults = getRawResults(interp);
+ 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 {
+ interp.execfile(script.openStream());
+ } catch (IOException e) {
+ logger.log(LogService.LOG_ERROR, "Unable to open jython script " +
+ script.toString() + ".", e);
+ e.printStackTrace();
+ }
+ 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
+ * after having executed a script)
+ * @return A list of objects, where each object is a result from
+ * the interpreters environment.
+ */
+ private List getRawResults(PythonInterpreter interp) {
+ List results = new ArrayList();
+
+ /*
+ * gets the values held in result variables, from
+ * "result0" counting upward, until we reach a result
+ * variable which is not defined.
+ */
+ int ii = 0;
+ String resultName = SCRIPT_RESULT_PREFIX + ii;
+
+ while (variableIsDefined(interp, resultName)) {
+
+ results.add(interp.get(resultName, Object.class));
+
+ ii++;
+ resultName = SCRIPT_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,
+ 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) {
+ 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.
|