/* @(#)$RCSfile$ * $Revision$ $Date$ $Author$ */ package de.mpicbg.knime.scripting.groovy; import java.io.File; import java.io.FilenameFilter; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; import org.eclipse.jface.preference.IPreferenceStore; import org.knime.core.node.BufferedDataTable; import org.knime.core.node.ExecutionContext; import org.knime.core.node.port.PortObject; import de.mpicbg.knime.scripting.core.AbstractScriptingNodeModel; import de.mpicbg.knime.scripting.core.ScriptingModelConfig; import de.mpicbg.knime.scripting.core.exceptions.KnimeScriptingException; import de.mpicbg.knime.scripting.groovy.prefs.GroovyScriptingPreferenceInitializer; import groovy.lang.Binding; import groovy.lang.GroovyShell; /** * This is the base implementation of the "JPython Script" node * * @author Tripos */ public class GroovyScriptNodeModel extends AbstractScriptingNodeModel { public static final String DEFAULT_SCRIPT = "//additional imports\n" + "import org.knime.core.data.DataColumnSpecCreator;\n" + "import org.knime.core.data.DataColumnSpec;\n\n" + "// create new output table spec\n" + "DataColumnSpecCreator c = new DataColumnSpecCreator(\"table name\", StringCell.TYPE);\n" + "DataColumnSpec cSpec1 = c.createSpec();\n" + "c = new DataColumnSpecCreator(\"number of columns\", IntCell.TYPE);\n" + "DataColumnSpec cSpec2 = c.createSpec();\n" + "c = new DataColumnSpecCreator(\"number of rows\", IntCell.TYPE);\n" + "DataColumnSpec cSpec3 = c.createSpec();\n\n" + "// open new output table container\n" + "DataTableSpec tSpec = new DataTableSpec(\"test\", cSpec1, cSpec2, cSpec3);\n" + "BufferedDataContainer con = exec.createDataContainer(tSpec);\n\n" + "// fill content from \"input\"\n" + "try {\n" + " DataTableSpec iSpec = input.getDataTableSpec();\n" + " String name = iSpec.getName();\n" + " int rows = input.size();\n" + " int cols = iSpec.getNumColumns();\n" + " DataRow firstRow = new DefaultRow(new RowKey(\"first\"), new StringCell(name), new IntCell(cols), new IntCell(rows));\n" + " con.addRowToTable(firstRow);\n\n" + "} catch(e) {\n" + "}\n" + "// fill content from \"input2\"\n" + "try {\n" + " DataTableSpec iSpec = input2.getDataTableSpec();\n" + " String name = iSpec.getName();\n" + " int rows = input2.size();\n" + " int cols = iSpec.getNumColumns();\n" + " DataRow firstRow = new DefaultRow(new RowKey(\"second\"), new StringCell(name), new IntCell(cols), new IntCell(rows));\n" + " con.addRowToTable(firstRow);\n\n" + "} catch(e) {\n" + "}\n\n" + "con.close()\n" + "return con.getTable();\n"; private static final String defaultImports = "import de.mpicbg.knime.knutils.Attribute\n" + "import de.mpicbg.knime.knutils.AttributeUtils\n" + "import de.mpicbg.knime.knutils.InputTableAttribute\n" + "import de.mpicbg.knime.knutils.TableUpdateCache\n" + "import org.knime.core.data.DataCell\n" + "import org.knime.core.data.def.StringCell\n" + "import org.knime.core.data.def.DoubleCell\n" + "import org.knime.core.data.def.IntCell\n" + "import org.knime.core.data.DataRow\n" + "import org.knime.core.data.DataType\n" + "import org.knime.core.data.DataTableSpec\n" + "import org.knime.core.data.RowKey\n" + "import org.knime.core.data.def.DefaultRow\n" + "import org.knime.core.data.def.StringCell\n" + "import org.knime.core.node.BufferedDataContainer\n" + "import org.knime.core.node.BufferedDataTable\n" + "import org.knime.core.node.ExecutionContext\n\n" + "import org.knime.core.node.CanceledExecutionException\n\n"; private static ScriptingModelConfig nodeModelConfig = new ScriptingModelConfig( createPorts(2, 1,2), // 2 inputs, both optional createPorts(1), // 1 output table new GroovyColumnSupport(), true, // use script false, // open in functionality false); // use chunk settings /** * {@inheritDoc} */ public GroovyScriptNodeModel() { super(nodeModelConfig); } @Override /** * {@inheritDoc} */ public String getDefaultScript(String defaultScript) { return DEFAULT_SCRIPT; } private ClassLoader createClassLoader() throws MalformedURLException { IPreferenceStore prefStore = GroovyScriptingBundleActivator.getDefault().getPreferenceStore(); String classpathAddons = prefStore.getString(GroovyScriptingPreferenceInitializer.GROOVY_CLASSPATH_ADDONS); classpathAddons.replace("\n", ";"); List<URL> urls = new ArrayList<URL>(); for (String classPathEntry : classpathAddons.split(";")) { classPathEntry = classPathEntry.trim(); if (classPathEntry.trim().startsWith("#")) continue; // replace patterns classPathEntry = classPathEntry.replace("{KNIME.HOME}", System.getProperty("osgi.syspath")); try { if (classPathEntry.endsWith("*")) { FilenameFilter jarFilter = new FilenameFilter() { public boolean accept(File file, String s) { return s.endsWith(".jar"); } }; for (File file : new File(classPathEntry).getParentFile().listFiles(jarFilter)) { urls.add(file.toURI().toURL()); } } else { File file = new File(classPathEntry); if (file.exists()) { urls.add(file.toURI().toURL()); } } } catch (Throwable t) { logger.error("The url '" + classPathEntry + "' does not exist. Please correct the entry in Preferences > KNIME > Groovy Scripting"); } } return new URLClassLoader(urls.toArray(new URL[0]), this.getClass().getClassLoader()); } /** * {@inheritDoc} */ @Override protected PortObject[] executeImpl(PortObject[] inData, ExecutionContext exec) throws Exception { BufferedDataTable in1; BufferedDataTable in2; // create the groovy enviroment and execute the script Binding binding = new Binding(); switch (getNrInPorts()) { case 2: in2 = (BufferedDataTable) inData[1]; binding.setVariable("input2", in2); // binding.setVariable("attributes2", Attribute.convert(in2.getDataTableSpec())); case 1: in1 = (BufferedDataTable) inData[0]; binding.setVariable("input", in1); // binding.setVariable("attributes", Attribute.convert(in1.getDataTableSpec())); case 0: break; } // register the exec (in case the script needs to create a new table binding.setVariable("exec", exec); ClassLoader loader = createClassLoader(); GroovyShell shell = new GroovyShell(loader, binding); Object o; try { String script = prepareScript(); o = shell.evaluate(defaultImports + script); } catch (Throwable t) { throw new RuntimeException(t); } if (o == null) { throw new RuntimeException("No return value (of type BufferedDataTable"); } if (!(o instanceof BufferedDataTable)) { throw new RuntimeException("return value is not of expected type BufferedDataTable"); } BufferedDataTable outTable = (BufferedDataTable) o; return new BufferedDataTable[]{outTable}; } @Override protected void openIn(PortObject[] inData, ExecutionContext exec) throws KnimeScriptingException { throw new KnimeScriptingException("The functionality to open data external is not yet implemented"); } }