diff --git a/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/KnimeProcessorTest.java b/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/KnimeProcessorTest.java deleted file mode 100644 index 5127813..0000000 --- a/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/KnimeProcessorTest.java +++ /dev/null @@ -1,176 +0,0 @@ -package org.knime.scijava.commands.testing; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.knime.core.data.DataCell; -import org.knime.core.data.DataRow; -import org.knime.core.data.DataTableSpec; -import org.knime.core.data.DataType; -import org.knime.core.data.RowKey; -import org.knime.core.data.def.BooleanCell; -import org.knime.core.data.def.DefaultRow; -import org.knime.core.data.def.IntCell; -import org.knime.core.data.def.LongCell; -import org.knime.core.data.def.StringCell; -import org.knime.scijava.commands.converter.ConverterCacheService; -import org.knime.scijava.commands.io.DefaultInputDataRowService; -import org.knime.scijava.commands.io.DefaultOutputDataRowService; -import org.knime.scijava.commands.io.InputDataRowService; -import org.knime.scijava.commands.io.OutputDataRowService; -import org.knime.scijava.commands.process.DefaultKnimePostprocessor; -import org.knime.scijava.core.ResourceAwareClassLoader; -import org.scijava.Context; -import org.scijava.ItemIO; -import org.scijava.command.Command; -import org.scijava.command.CommandModule; -import org.scijava.command.CommandService; -import org.scijava.plugin.DefaultPluginFinder; -import org.scijava.plugin.Parameter; -import org.scijava.plugin.PluginIndex; -import org.scijava.service.Service; - -/** - * Test for {@link ColumnInputMappingKnimePreprocessor} and - * {@link DefaultKnimePostprocessor}. - * - * @author Jonathan Hale (University of Konstanz) - */ -public class KnimeProcessorTest { - - private static Context context; - - @Parameter - CommandService m_commandService; - @Parameter - InputDataRowService m_inputRowService; - @Parameter - OutputDataRowService m_outputCellsService; - - protected static List> requiredServices = Arrays.> asList( - DefaultInputDataRowService.class, DefaultOutputDataRowService.class, CommandService.class, - ConverterCacheService.class); - - // Create the test table - private static final DataRow m_testRow = new DefaultRow(new RowKey("TestRow001"), BooleanCell.TRUE, new IntCell(42), - new IntCell(420), new IntCell(42000), new LongCell(4200000), new StringCell("KNIME"), new StringCell(" ")); - - private static final DataTableSpec m_spec = new DataTableSpec(new String[] { "b", "by", "s", "i", "l", "str", "c" }, - new DataType[] { BooleanCell.TYPE, IntCell.TYPE, IntCell.TYPE, IntCell.TYPE, LongCell.TYPE, StringCell.TYPE, - StringCell.TYPE }); - - @BeforeClass - public static void setUpOnce() { - ResourceAwareClassLoader cl = new ResourceAwareClassLoader(Thread.currentThread().getContextClassLoader()); - - context = new Context(requiredServices, new PluginIndex(new DefaultPluginFinder(cl))); - } - - @AfterClass - public static void tearDown() { - context.dispose(); - } - - @Before - public void setUp() { - context.inject(this); - } - - @Test - public void testModuleProcessing() throws InterruptedException, ExecutionException { - assertNotNull(m_inputRowService); - assertNotNull(m_outputCellsService); - assertNotNull(m_commandService); - m_inputRowService.setInputDataRow(m_testRow); - m_inputRowService.setDataTableSpec(m_spec); - - Future command = m_commandService.run(MyCommand.class, true); - assertNotNull(command); - CommandModule commandModule = command.get(); - assertNotNull(commandModule); - assertFalse("Command was cancelled: " + commandModule.getCancelReason(), commandModule.isCanceled()); - - DataCell[] cells = m_outputCellsService.getOutputDataCells(); - assertNotNull(cells); - assertEquals(7, cells.length); - - assertTrue("Boolean output was not extracted correctly!", ((BooleanCell) cells[0]).getBooleanValue()); - assertEquals("Byte output was not extracted correctly!", 42, ((IntCell) cells[1]).getIntValue()); - assertEquals("Short output was not extracted correctly!", 420, ((IntCell) cells[2]).getIntValue()); - assertEquals("Integer output was not extracted correctly!", 42000, ((IntCell) cells[3]).getIntValue()); - assertEquals("Long output was not extracted correctly!", 4200000, ((LongCell) cells[4]).getLongValue()); - assertEquals("String output was not extracted correctly!", "KNIME", ((StringCell) cells[5]).getStringValue()); - assertEquals("Character output was not extracted correctly!", " ", ((StringCell) cells[6]).getStringValue()); - } - - /** - * Test command which verifies that inputs have been filled by the - * preprocessor and feeds them directly back in the outputs which can then - * be collected into a data row. - * - * @author Jonathan Hale - */ - public static class MyCommand implements Command { - - @Parameter(type = ItemIO.INPUT) - Boolean b; - @Parameter(type = ItemIO.INPUT) - Byte by; - @Parameter(type = ItemIO.INPUT) - Short s; - @Parameter(type = ItemIO.INPUT) - Integer i; - @Parameter(type = ItemIO.INPUT) - Long l; - @Parameter(type = ItemIO.INPUT) - String str; - @Parameter(type = ItemIO.INPUT) - Character c; - - @Parameter(type = ItemIO.OUTPUT) - Boolean ob; - @Parameter(type = ItemIO.OUTPUT) - Byte oby; - @Parameter(type = ItemIO.OUTPUT) - Short os; - @Parameter(type = ItemIO.OUTPUT) - Integer oi; - @Parameter(type = ItemIO.OUTPUT) - Long ol; - @Parameter(type = ItemIO.OUTPUT) - String ostr; - @Parameter(type = ItemIO.OUTPUT) - Character oc; - - @Override - public void run() { - assertTrue("Boolean input was not filled correctly!", b); - assertEquals("Byte input was not filled correctly!", new Byte((byte) 42), by); - assertEquals("Short input was not filled correctly!", new Short((short) 420), s); - assertEquals("Integer input was not filled correctly!", new Integer(42000), i); - assertEquals("Long input was not filled correctly!", new Long(4200000), l); - assertEquals("String input was not filled correctly!", "KNIME", str); - assertEquals("Character input was not filled correctly!", new Character(' '), c); - - ob = b; - oby = by; - os = s; - oi = i; - ol = l; - ostr = str; - oc = c; - } - - } -} diff --git a/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/NodeModuleTest.java b/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/NodeModuleTest.java new file mode 100644 index 0000000..2a12215 --- /dev/null +++ b/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/NodeModuleTest.java @@ -0,0 +1,165 @@ +package org.knime.scijava.commands.testing; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.knime.core.data.DataCell; +import org.knime.core.data.DataRow; +import org.knime.core.data.DataTableSpec; +import org.knime.core.data.DataType; +import org.knime.core.data.MissingCell; +import org.knime.core.data.RowKey; +import org.knime.core.data.def.BooleanCell; +import org.knime.core.data.def.DefaultRow; +import org.knime.core.data.def.IntCell; +import org.knime.core.data.def.LongCell; +import org.knime.core.data.def.StringCell; +import org.knime.core.node.NodeLogger; +import org.knime.core.node.defaultnodesettings.SettingsModel; +import org.knime.core.node.defaultnodesettings.SettingsModelBoolean; +import org.knime.core.node.defaultnodesettings.SettingsModelString; +import org.knime.scijava.commands.CellOutput; +import org.knime.scijava.commands.SciJavaGateway; +import org.knime.scijava.commands.module.NodeModule; +import org.knime.scijava.commands.module.NodeModuleService; +import org.knime.scijava.commands.settings.models.SettingsModelColumnSelection; +import org.scijava.Context; +import org.scijava.command.CommandInfo; +import org.scijava.plugin.Parameter; + +/** + * Test for {@link ColumnInputMappingKnimePreprocessor} and + * {@link DefaultKnimePostprocessor}. + * + * @author Jonathan Hale (University of Konstanz) + */ +public class NodeModuleTest { + + static Context context; + + @Parameter + NodeModuleService m_nodeModuleService; + + // Create the test table + final String[] inputNames = new String[] { "b", "i", "l", "str" }; + final String[] outputNames = new String[] { "ob", "oi", "ol", "ostr" }; + + final DataType[] inputDataTypes = new DataType[] { BooleanCell.TYPE, IntCell.TYPE, LongCell.TYPE, StringCell.TYPE }; + final DataTableSpec m_spec = new DataTableSpec(new String[] { "b", "i", "l", "str" }, inputDataTypes); + final DataType[] expectedOutputDataTypes = new DataType[] { BooleanCell.TYPE, IntCell.TYPE, LongCell.TYPE, + StringCell.TYPE }; + + @BeforeClass + public static void setUpOnce() { + context = SciJavaGateway.get().getGlobalContext(); + } + + @Before + public void setUp() { + context.inject(this); + } + + /** + * Create a NodeModule + * @param emptyTest Whether to have the module check for correct input values + * @return the created Module + */ + private NodeModule createNodeModule(boolean emptyTest) { + final HashMap settings = new HashMap(); + for (final String name : inputNames) { + settings.put(name, new SettingsModelColumnSelection(name, name)); + } + + settings.put("emptyTest", new SettingsModelBoolean("emptyTest", emptyTest)); + + for (int i = 0; i < outputNames.length; ++i) { + settings.put(outputNames[i], new SettingsModelString(outputNames[i], expectedOutputDataTypes[i].getName())); + } + + return m_nodeModuleService.createNodeModule(new CommandInfo(ScijavaTestCommand.class), settings, m_spec, + NodeLogger.getLogger(NodeModuleTest.class)); + } + + @Test + public void testExecution() throws Exception { + final NodeModule nodeModule = createNodeModule(false); + + final DataRow testRow = new DefaultRow( // + new RowKey("TestRow001"), // + BooleanCell.TRUE, // + new IntCell(42000), // + new LongCell(4200000), // + new StringCell("KNIME")); + + final ArrayList cells = new ArrayList<>(); + final CellOutput cellOutput = new CellOutput() { + + final ArrayList m_cells = cells; + + @Override + public void push(DataCell[] cells) throws InterruptedException { + assertNotNull(cells); + assertEquals("Unexpected amout of cells pushed.", 4, cells.length); + + assertEquals("Unexpected type for pushed cell.", BooleanCell.class, cells[0].getClass()); + assertEquals("Unexpected type for pushed cell.", IntCell.class, cells[1].getClass()); + assertEquals("Unexpected type for pushed cell.", LongCell.class, cells[2].getClass()); + assertEquals("Unexpected type for pushed cell.", StringCell.class, cells[3].getClass()); + + assertTrue("Boolean output was not extracted correctly!", ((BooleanCell) cells[0]).getBooleanValue()); + assertEquals("Integer output was not extracted correctly!", 42000, ((IntCell) cells[1]).getIntValue()); + assertEquals("Long output was not extracted correctly!", 4200000, ((LongCell) cells[2]).getLongValue()); + assertEquals("String output was not extracted correctly!", "KNIME", + ((StringCell) cells[3]).getStringValue()); + + m_cells.add(cells); + } + }; + + nodeModule.run(testRow, cellOutput, null); + + assertFalse("No cells were pushed", cells.isEmpty()); + } + + @Test + public void testMissings() throws Exception { + final NodeModule nodeModule = createNodeModule(true); + + final DataRow emptyRow = new DefaultRow( // + new RowKey("TestRow001"), // + new MissingCell("Nothing here."), // + new MissingCell("Nothing here either."), // + new MissingCell("Full of nihilism."), // + new MissingCell("Void.")); + + final ArrayList cells = new ArrayList<>(); + final CellOutput cellOutput = new CellOutput() { + + final ArrayList m_cells = cells; + + @Override + public void push(DataCell[] cells) throws InterruptedException { + assertNotNull(cells); + assertEquals("Unexpected amout of cells pushed.", 4, cells.length); + + for (DataCell cell : cells) { + assertEquals("Unexpected type for pushed cell.", MissingCell.class, cell.getClass()); + } + + m_cells.add(cells); + } + }; + + nodeModule.run(emptyRow, cellOutput, null); + + assertFalse("No cells were pushed", cells.isEmpty()); + } +} diff --git a/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/ScijavaTestCommand.java b/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/ScijavaTestCommand.java new file mode 100644 index 0000000..4eb468d --- /dev/null +++ b/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/ScijavaTestCommand.java @@ -0,0 +1,61 @@ +package org.knime.scijava.commands.testing; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.knime.scijava.commands.StyleHook; +import org.scijava.ItemIO; +import org.scijava.command.Command; +import org.scijava.plugin.Parameter; + +/** + * Test command which verifies that inputs have been filled by the preprocessor + * and feeds them directly back in the outputs which can then be collected into + * a data row. + * + * @author Jonathan Hale + */ +public class ScijavaTestCommand implements Command { + + @Parameter(type = ItemIO.INPUT) + Boolean emptyTest; + + @Parameter(type = ItemIO.INPUT, style = StyleHook.COLUMNSELECTION) + Boolean b; + @Parameter(type = ItemIO.INPUT, style = StyleHook.COLUMNSELECTION) + Integer i; + @Parameter(type = ItemIO.INPUT, style = StyleHook.COLUMNSELECTION) + Long l; + @Parameter(type = ItemIO.INPUT, style = StyleHook.COLUMNSELECTION) + String str; + + @Parameter(type = ItemIO.OUTPUT) + Boolean ob; + @Parameter(type = ItemIO.OUTPUT) + Integer oi; + @Parameter(type = ItemIO.OUTPUT) + Long ol; + @Parameter(type = ItemIO.OUTPUT) + String ostr; + + @Override + public void run() { + if (!emptyTest) { + assertTrue("Boolean input was not filled correctly!", b); + assertEquals("Integer input was not filled correctly!", new Integer(42000), i); + assertEquals("Long input was not filled correctly!", new Long(4200000), l); + assertEquals("String input was not filled correctly!", "KNIME", str); + } else { + assertEquals("Integer input was not filled correctly!", null, b); + assertEquals("Integer input was not filled correctly!", null, i); + assertEquals("Long input was not filled correctly!", null, l); + assertEquals("String input was not filled correctly!", null, str); + } + + ob = b; + oi = i; + ol = l; + ostr = str; + } + +} \ No newline at end of file diff --git a/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/services/DefaultNodeModuleServiceTest.java b/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/services/DefaultNodeModuleServiceTest.java new file mode 100644 index 0000000..600a9e4 --- /dev/null +++ b/org.knime.scijava.commands.testing/src/org/knime/scijava/commands/testing/services/DefaultNodeModuleServiceTest.java @@ -0,0 +1,80 @@ +package org.knime.scijava.commands.testing.services; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.HashMap; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.knime.core.data.DataTableSpec; +import org.knime.core.data.DataType; +import org.knime.core.data.def.BooleanCell; +import org.knime.core.data.def.IntCell; +import org.knime.core.data.def.LongCell; +import org.knime.core.data.def.StringCell; +import org.knime.core.node.defaultnodesettings.SettingsModel; +import org.knime.core.node.defaultnodesettings.SettingsModelString; +import org.knime.scijava.commands.SciJavaGateway; +import org.knime.scijava.commands.module.NodeModuleService; +import org.knime.scijava.commands.settings.models.SettingsModelColumnSelection; +import org.knime.scijava.commands.testing.ScijavaTestCommand; +import org.scijava.Context; +import org.scijava.command.CommandInfo; +import org.scijava.plugin.Parameter; + +/** + * Test for {@link NodeModuleService}. + * + * @author Jonathan Hale (University of Konstanz) + */ +public class DefaultNodeModuleServiceTest { + + private static Context context; + + @Parameter + NodeModuleService m_nodeModuleService; + + private final DataTableSpec inSpec = new DataTableSpec(new String[] { "b", "i", "l", "str" }, + new DataType[] { BooleanCell.TYPE, IntCell.TYPE, LongCell.TYPE, StringCell.TYPE }); + + @BeforeClass + public static void setUpOnce() { + context = SciJavaGateway.get().getGlobalContext(); + } + + @Before + public void setUp() { + context.inject(this); + assertNotNull(m_nodeModuleService); + } + + @Test + public void testCreateOutSpec() throws Exception { + /* + * Create settings which just map input columns to equally named module + * items. + */ + final HashMap settings = new HashMap(); + for (final String name : new String[] { "b", "i", "l", "str" }) { + settings.put(name, new SettingsModelColumnSelection(name, name)); + } + + String[] outNames = new String[] { "ob", "oi", "ol", "ostr" }; + DataType[] outTypes = new DataType[] { BooleanCell.TYPE, IntCell.TYPE, LongCell.TYPE, StringCell.TYPE }; + for (int i = 0; i < outNames.length; ++i) { + settings.put(outNames[i], new SettingsModelString(outNames[i], outTypes[i].getName())); + } + + // Produce output column spec + DataTableSpec outSpec = m_nodeModuleService.createOutSpec(new CommandInfo(ScijavaTestCommand.class), settings, + inSpec); + + assertArrayEquals("Names for output columns are incorrect.", outNames, outSpec.getColumnNames()); + for (int i = 0; i < outNames.length; ++i) { + assertEquals("Type for column " + i + " is incorrect.", outTypes[i], outSpec.getColumnSpec(i).getType()); + } + } +} diff --git a/org.knime.scijava.commands/.classpath b/org.knime.scijava.commands/.classpath index 20fefe5..e95569f 100644 --- a/org.knime.scijava.commands/.classpath +++ b/org.knime.scijava.commands/.classpath @@ -3,5 +3,6 @@ + diff --git a/org.knime.scijava.commands/META-INF/MANIFEST.MF b/org.knime.scijava.commands/META-INF/MANIFEST.MF index 2182c6c..a2df331 100644 --- a/org.knime.scijava.commands/META-INF/MANIFEST.MF +++ b/org.knime.scijava.commands/META-INF/MANIFEST.MF @@ -16,10 +16,16 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.11.0", scijava-plugins-text-plain;bundle-version="0.1.2", scijava-ui-awt;bundle-version="0.1.4", scijava-ui-swing;bundle-version="0.8.0", - org.knime.scijava.core;bundle-version="0.2.1" + org.knime.scijava.core;bundle-version="0.2.1", + com.google.guava;bundle-version="19.0.0", + scripting-jython;bundle-version="0.3.0", + jython-shaded;bundle-version="2.5.3", + scripting-java;bundle-version="0.4.0", + scripting-clojure;bundle-version="0.1.4" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy -Bundle-ClassPath: scijava_commands.jar +Bundle-ClassPath: scijava_commands.jar, + lib/tools.jar Export-Package: org.knime.scijava.commands, org.knime.scijava.commands.adapter, org.knime.scijava.commands.adapter.basic, diff --git a/org.knime.scijava.commands/build.properties b/org.knime.scijava.commands/build.properties index fa96c6d..df3e6a2 100644 --- a/org.knime.scijava.commands/build.properties +++ b/org.knime.scijava.commands/build.properties @@ -6,7 +6,8 @@ bin.includes = plugin.xml,\ lib/,\ icons/,\ lib/mvn/scijava-common-2.1.0.jar,\ - scijava_commands.jar + scijava_commands.jar,\ + lib/tools.jar output.knipknime.jar = bin/ src.includes = lib/src/,\ src/ diff --git a/org.knime.scijava.commands/lib/tools.jar b/org.knime.scijava.commands/lib/tools.jar new file mode 100644 index 0000000..b7a0156 Binary files /dev/null and b/org.knime.scijava.commands/lib/tools.jar differ diff --git a/org.knime.scijava.commands/plugin.xml b/org.knime.scijava.commands/plugin.xml index 4d8a631..c877a52 100644 --- a/org.knime.scijava.commands/plugin.xml +++ b/org.knime.scijava.commands/plugin.xml @@ -1,4 +1,16 @@ + + + + + + diff --git a/org.knime.scijava.commands/scripts/myjython.py b/org.knime.scijava.commands/scripts/myjython.py new file mode 100644 index 0000000..0759dc4 --- /dev/null +++ b/org.knime.scijava.commands/scripts/myjython.py @@ -0,0 +1,6 @@ +# @double value +# @OUTPUT double greeting + +greeting = value + +print greeting diff --git a/org.knime.scijava.commands/scripts/test.clj b/org.knime.scijava.commands/scripts/test.clj new file mode 100644 index 0000000..41e0cad --- /dev/null +++ b/org.knime.scijava.commands/scripts/test.clj @@ -0,0 +1,4 @@ +; @Integer(label="My integer",description="Input integer.",value=17) test-int +; @OUTPUT Integer output-int + +(def output-int test-int) diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/CellOutput.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/CellOutput.java new file mode 100644 index 0000000..394ce9a --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/CellOutput.java @@ -0,0 +1,20 @@ +package org.knime.scijava.commands; + +import org.knime.core.data.DataCell; + +/** + * Interface for classes which are able to receive cells as output. + * + * @author Christian Dietz, University of Konstanz + */ +public interface CellOutput { + + /** + * Push a new row of output. + * + * @param cells + * The cells which make the output row + * @throws InterruptedException If canceled. + */ + void push(final DataCell[] cells) throws InterruptedException; +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/DefaultKnimeExecutionService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/DefaultKnimeExecutionService.java deleted file mode 100644 index 8810acf..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/DefaultKnimeExecutionService.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.knime.scijava.commands; - -import java.lang.ref.WeakReference; - -import org.knime.core.node.ExecutionContext; -import org.scijava.Priority; -import org.scijava.plugin.Plugin; -import org.scijava.service.AbstractService; - -/** - * Default implementation of KnimeExecutionService. Holds a KNIME Node - * {@link ExecutionContext} in a {@link WeakReference}, which ensures that the - * {@link ExecutionContext} can be garbage collected when execution of a Node - * terminates. - * - * @author Jonathan Hale (University of Konstanz) - * @see ExecutionContext - */ -@Plugin(type = KNIMEExecutionService.class, priority = DefaultKnimeExecutionService.PRIORITY) -public class DefaultKnimeExecutionService extends AbstractService - implements KNIMEExecutionService { - - /** - * Priority of this {@link Plugin} - */ - public static final double PRIORITY = Priority.NORMAL_PRIORITY; - - private WeakReference m_exec = new WeakReference<>(null); - - /** - * Set the {@link ExecutionContext}. Note that this service holds the - * {@link ExecutionContext} in a {@link WeakReference}, which means that the - * reference needs to be kept valid outside the service. - * - * @param context - */ - @Override - public void setExecutionContext(final ExecutionContext context) { - m_exec = new WeakReference<>(context); - } - - @Override - public ExecutionContext getExecutionContext() { - return m_exec.get(); - } - -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/KNIMEExecutionService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/KNIMEExecutionService.java deleted file mode 100644 index b5ec4f4..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/KNIMEExecutionService.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.knime.scijava.commands; - -import org.knime.core.node.ExecutionContext; -import org.scijava.plugin.Plugin; -import org.scijava.service.Service; - -/** - * Service holding an {@link ExecutionContext} - * - *

- * KnimeExecutionService plugins discoverable at runtime must implement this - * interface and be annotated with @{@link Plugin} with attribute - * {@link Plugin#type()} = {@link KNIMEExecutionService}.class. - *

- * - * @author Jonathan Hale (University of Konstanz) - * - */ -public interface KNIMEExecutionService extends Service { - - /** - * @return the ExecutionContext held by this service, or null if there is - * none. - */ - ExecutionContext getExecutionContext(); - - /** - * Set the ExecutionContext for this service to hold. - * @param context - */ - void setExecutionContext(ExecutionContext context); - -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/KNIMESciJavaConstants.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/KNIMESciJavaConstants.java deleted file mode 100644 index ef3d7c5..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/KNIMESciJavaConstants.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.knime.scijava.commands; - -public final class KNIMESciJavaConstants { - - public static final String COLUMN_SELECT_KEY = "columnSelect"; - public static final String DEFAULT_COLUMN_KEY = "defaultColumn"; - - private KNIMESciJavaConstants() { - // NB Utility class. - } - -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/MultiOutputListener.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/MultiOutputListener.java new file mode 100644 index 0000000..c108468 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/MultiOutputListener.java @@ -0,0 +1,16 @@ +package org.knime.scijava.commands; + +/** + * Interface for classes which listen to pushes of output rows. + * + * @author Christian Dietz, University of Konstanz + * @see CellOutput + */ +public interface MultiOutputListener { + + /** + * Notify this listener that a new output row has been pushed. + * @throws Exception + */ + public void notifyListener() throws Exception; +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/SciJavaGateway.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/SciJavaGateway.java index f0b8102..9b3970b 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/SciJavaGateway.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/SciJavaGateway.java @@ -3,14 +3,10 @@ import java.util.Arrays; import java.util.List; -import org.knime.scijava.commands.converter.ConverterCacheService; -import org.knime.scijava.commands.io.InputDataRowService; -import org.knime.scijava.commands.io.OutputDataRowService; -import org.knime.scijava.commands.settings.NodeModelSettingsService; +import org.knime.scijava.commands.converter.KNIMEConverterService; +import org.knime.scijava.commands.module.NodeModuleService; import org.knime.scijava.commands.settings.NodeSettingsService; import org.knime.scijava.commands.settings.SettingsModelTypeService; -import org.knime.scijava.commands.simplemapping.SimpleColumnMappingService; -import org.knime.scijava.commands.widget.KNIMEWidgetService; import org.knime.scijava.core.ResourceAwareClassLoader; import org.knime.scijava.core.SubContext; import org.knime.scijava.core.pluginindex.ReusablePluginIndex; @@ -22,12 +18,15 @@ import org.scijava.plugin.PluginIndex; import org.scijava.plugin.PluginService; import org.scijava.prefs.PrefService; +import org.scijava.script.ScriptService; import org.scijava.service.Service; import org.scijava.ui.UIService; import org.scijava.widget.WidgetService; /** - * Gateway to the SciJava world + * Gateway to the SciJava world. + * + * @author Christian Dietz, University of Konstanz */ public class SciJavaGateway { @@ -50,15 +49,11 @@ public class SciJavaGateway { /** a list of services which need to be present in newly created contexts */ protected static List> requiredServices = Arrays - .> asList(InputDataRowService.class, - OutputDataRowService.class, PrefService.class, - KNIMEExecutionService.class, NodeSettingsService.class, - ObjectService.class, WidgetService.class, - KNIMEWidgetService.class, UIService.class, - ConverterCacheService.class, CommandService.class, - NodeModelSettingsService.class, - SettingsModelTypeService.class, - SimpleColumnMappingService.class); + .> asList(PrefService.class, + ObjectService.class, WidgetService.class, UIService.class, + KNIMEConverterService.class, CommandService.class, + NodeModuleService.class, SettingsModelTypeService.class, + NodeSettingsService.class, ScriptService.class); /** * Constructor. Only to be called from {@link #get()}. @@ -101,7 +96,7 @@ public Context createSubContext() { return context; } - private Context getGlobalContext() { + public Context getGlobalContext() { if (m_globalContext == null) { m_globalContext = new Context(m_pluginIndex); @@ -117,5 +112,4 @@ private Context getGlobalContext() { public ResourceAwareClassLoader getClassLoader() { return m_classLoader; } - } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/SciJavaTestCommand.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/SciJavaTestCommand.java new file mode 100644 index 0000000..ddf39ec --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/SciJavaTestCommand.java @@ -0,0 +1,40 @@ + +package org.knime.scijava.commands; + +import org.scijava.ItemIO; +import org.scijava.command.Command; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; + +/** + * + * Example Command to be wrapped as KNIME Node. + * + * @author Christian Dietz, University of Konstanz + */ +@Plugin(type = Command.class, headless = true, label = "Test Command") +public class SciJavaTestCommand implements Command { + @Parameter + private MultiOutputListener rowOutput; + + @Parameter(label = "From Text", style = StyleHook.COLUMNSELECTION) + private String fromText; + + @Parameter(label = "From Int") + private int fromInt; + + @Parameter(type = ItemIO.OUTPUT, label = "Output Int") + private int outInt; + + @Override + public void run() { + try { + for (int i = 0; i < fromInt; i++) { + outInt = i; + rowOutput.notifyListener(); + } + } catch (final Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/StyleHook.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/StyleHook.java new file mode 100644 index 0000000..cf21f0f --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/StyleHook.java @@ -0,0 +1,17 @@ +package org.knime.scijava.commands; + +import org.knime.scijava.commands.widget.ColumnSelectionWidget; +import org.scijava.plugin.Parameter; + +/** + * StyleHook constants for {@link Parameter#style()}. + * + * @author Christian Dietz, University of Konstanz + */ +public interface StyleHook { + /** + * Force the parameter to be filled by a input column. Will result in the + * {@link ColumnSelectionWidget} being used as for it. + */ + public final static String COLUMNSELECTION = "colSel"; +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/converter/DefaultConverterCacheService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/converter/DefaultKNIMEConverterService.java similarity index 53% rename from org.knime.scijava.commands/src/org/knime/scijava/commands/converter/DefaultConverterCacheService.java rename to org.knime.scijava.commands/src/org/knime/scijava/commands/converter/DefaultKNIMEConverterService.java index 6fe7d04..e3e47d9 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/converter/DefaultConverterCacheService.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/converter/DefaultKNIMEConverterService.java @@ -1,9 +1,12 @@ package org.knime.scijava.commands.converter; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Optional; +import java.util.Set; import org.knime.core.data.DataCell; import org.knime.core.data.DataType; @@ -14,8 +17,8 @@ import org.knime.core.data.convert.java.DataCellToJavaConverter; import org.knime.core.data.convert.java.DataCellToJavaConverterFactory; import org.knime.core.data.convert.java.DataCellToJavaConverterRegistry; -import org.knime.scijava.commands.KNIMEExecutionService; -import org.scijava.plugin.Parameter; +import org.knime.core.data.convert.util.ClassUtil; +import org.knime.core.node.ExecutionContext; import org.scijava.plugin.Plugin; import org.scijava.service.AbstractService; @@ -23,11 +26,10 @@ * Caches the converters used in a Node. * * @author Gabriel Einsdorf (University of Konstanz) - * */ -@Plugin(type = ConverterCacheService.class) -public class DefaultConverterCacheService extends AbstractService - implements ConverterCacheService { +@Plugin(type = KNIMEConverterService.class) +public class DefaultKNIMEConverterService extends AbstractService + implements KNIMEConverterService { private final DataCellToJavaConverterRegistry m_inRegister = DataCellToJavaConverterRegistry .getInstance(); @@ -35,10 +37,6 @@ public class DefaultConverterCacheService extends AbstractService .getInstance(); private final Map> m_inConverters = new HashMap<>(); - private final Map> m_outConverters = new HashMap<>(); - - @Parameter - private KNIMEExecutionService m_execService; @Override @SuppressWarnings("unchecked") @@ -54,43 +52,40 @@ public O convertToJava(final DataCell cell, final Class outputType) } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) - public DataCell convertToKnime(final Object in, final Class inType) - throws Exception { + @SuppressWarnings("unchecked") + public DataCell convertToKnime(final Object in, final Class inType, + final DataType type, final ExecutionContext ctx) throws Exception { - final String key = createOutputKey(inType); + final JavaToDataCellConverter converter = (JavaToDataCellConverter) createNewOutputConverter( + inType, type, ctx); - final JavaToDataCellConverter converter = m_outConverters - .getOrDefault(key, addNewOutputConverter(inType)); return converter.convert(in); } - private String createOutputKey(final Class inType) { - return inType.getName(); - } + /* + * Create new converter from given java type to output knime DataType. + */ + private JavaToDataCellConverter createNewOutputConverter( + final Class type, final DataType knimeType, + final ExecutionContext ctx) { - private JavaToDataCellConverter addNewOutputConverter( - final Class outputType) { + final Class outputType = ClassUtil + .ensureObjectType(type); - // TODO Will this use the "Best" dataType? - final Iterator> factoriesIt = m_outRegistry - .getFactoriesForSourceType(outputType).iterator(); + // TODO is this the best converter? + final Collection> factories = m_outRegistry + .getConverterFactories(type, knimeType); - if (!factoriesIt.hasNext()) { - throw new IllegalArgumentException("Can't convert from: " - + outputType.getName() + " to a KNIME datatype"); + if (!factories.isEmpty()) { + return factories.iterator().next().create(ctx); } - final JavaToDataCellConverter factory = factoriesIt.next() - .create(m_execService.getExecutionContext()); - final String key = createOutputKey(outputType); - m_outConverters.put(key, factory); - - return factory; + throw new IllegalArgumentException("Can't convert from: " + + outputType.getName() + " to a KNIME datatype"); } /** - * Adds the converter to the cache. + * Add the converter to the cache. * * @param inputType * @param outputType @@ -99,17 +94,22 @@ private JavaToDataCellConverter addNewOutputConverter( private DataCellToJavaConverter addNewInputConverter( final DataType inputType, final Class outputType) { - final Optional> factory = m_inRegister.getPreferredConverterFactory(inputType, outputType); + final Optional> factory = m_inRegister + .getPreferredConverterFactory(inputType, outputType); if (!factory.isPresent()) { throw new IllegalArgumentException("Can't convert from: " + inputType.getName() + " to :" + outputType.getName()); } - final DataCellToJavaConverter conv = factory.get().create(); + final DataCellToJavaConverter conv = factory + .get().create(); m_inConverters.put(createInputKey(inputType, outputType), conv); return conv; } + /* + * Create a string key for the (knime type, java type) pair + */ private static String createInputKey(final DataType dataType, final Class outputType) { return dataType.getName() + ":" + outputType.getName(); @@ -118,8 +118,11 @@ private static String createInputKey(final DataType dataType, @Override public Optional getConvertedType(final Class type) { + final Class outputType = ClassUtil + .ensureObjectType(type); + final Iterator> it = m_outRegistry - .getFactoriesForSourceType(type).iterator(); + .getFactoriesForSourceType(outputType).iterator(); if (it.hasNext()) { final JavaToDataCellConverterFactory o = it.next(); @@ -130,7 +133,6 @@ public Optional getConvertedType(final Class type) { @Override public void flushCaches() { - m_outConverters.clear(); m_inConverters.clear(); } @@ -151,9 +153,6 @@ public Optional> getMatchingInputValueClass( @Override public Optional> getMatchingJavaType(final DataType dataType) { - - // FIXME Will this always work with the MissingValue <-> Object - // Converter? final Optional> o = m_inRegister .getFactoriesForSourceType(dataType).stream().findFirst(); if (o.isPresent()) { @@ -162,4 +161,49 @@ public Optional> getMatchingJavaType(final DataType dataType) { return Optional.empty(); } + @Override + public Collection> getMatchingJavaTypes( + final ClassLoader loader, final DataType dataType) { + final Collection> factories = m_inRegister + .getFactoriesForSourceType(dataType); + final Set> validFactories = new HashSet<>(); + + for (final DataCellToJavaConverterFactory candidate : factories) { + if (isOnClassPath(candidate.getDestinationType(), loader)) { + validFactories.add(candidate); + } + } + + return validFactories; + } + + /* + * Check whether the given class is on the classpath. + * + * @return true if the class is in given loader + */ + private boolean isOnClassPath(final Class type, + final ClassLoader loader) { + try { + // FIXME: check if there is a more efficient way to do it. + Class.forName(type.getName(), false, loader); + } catch (final ClassNotFoundException e) { + return false; + } + return true; + } + + @Override + public Collection> getMatchingFactories( + final Class javaType) { + return m_outRegistry.getFactoriesForSourceType( + ClassUtil.ensureObjectType(javaType)); + } + + @Override + public Optional getPreferredDataType(final Class type) { + return m_outRegistry.getFactoriesForSourceType(type).stream() + .findFirst().map(fac -> fac.getDestinationType()); + } + } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/converter/ConverterCacheService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/converter/KNIMEConverterService.java similarity index 51% rename from org.knime.scijava.commands/src/org/knime/scijava/commands/converter/ConverterCacheService.java rename to org.knime.scijava.commands/src/org/knime/scijava/commands/converter/KNIMEConverterService.java index 1e9d925..b6ab266 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/converter/ConverterCacheService.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/converter/KNIMEConverterService.java @@ -1,13 +1,25 @@ package org.knime.scijava.commands.converter; +import java.util.Collection; import java.util.Optional; import org.knime.core.data.DataCell; import org.knime.core.data.DataType; import org.knime.core.data.DataValue; +import org.knime.core.data.convert.datacell.JavaToDataCellConverterFactory; +import org.knime.core.data.convert.java.DataCellToJavaConverterFactory; +import org.knime.core.node.ExecutionContext; import org.scijava.service.Service; -public interface ConverterCacheService extends Service { +/** + * KNIME Converter Cache Service. + * + * Interface for services which are able to convert KNIME data cells into java + * types vice versa. + * + * @author Gabriel Einsdorf (University of Konstanz) + */ +public interface KNIMEConverterService extends Service { /** * Convert a KNIME cell to the fitting java type. @@ -35,7 +47,8 @@ public interface ConverterCacheService extends Service { * @throws Exception * When the conversion fails */ - DataCell convertToKnime(Object in, Class inType) throws Exception; + DataCell convertToKnime(Object in, Class inType, DataType type, + ExecutionContext es) throws Exception; /** * Flush all caches. @@ -67,7 +80,32 @@ public interface ConverterCacheService extends Service { * the preferred value class * @return the matching java type */ - Optional> getMatchingJavaType( - DataType dataType); + Optional> getMatchingJavaType(DataType dataType); + /** + * Get all converter factories which are able to convert given + * {@link DataType} to a java type. + * + * @return Collection of converter factories + */ + Collection> getMatchingJavaTypes( + ClassLoader loader, DataType dataType); + + /** + * Get all converter factories which are able to convert given java type to + * a {@link DataType}. + * + * @return Collection of converter factories + */ + Collection> getMatchingFactories( + Class javaType); + + /** + * Get the preferred {@link DataType} to convert a certain Java type into. + * + * @param type + * the Java type + * @return an optional DataType which the java type can be converted into. + */ + Optional getPreferredDataType(final Class type); } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/dialog/DefaultDialogService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/dialog/DefaultDialogService.java new file mode 100644 index 0000000..fcf5fec --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/dialog/DefaultDialogService.java @@ -0,0 +1,81 @@ +package org.knime.scijava.commands.dialog; + +import java.util.List; + +import javax.swing.JPanel; + +import org.knime.core.util.Pair; +import org.knime.scijava.commands.widget.SettingsModelWidgetModel; +import org.scijava.module.Module; +import org.scijava.module.ModuleException; +import org.scijava.module.ModuleInfo; +import org.scijava.module.ModuleItem; +import org.scijava.module.ModuleService; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; +import org.scijava.service.AbstractService; +import org.scijava.ui.swing.widget.SwingInputHarvester; +import org.scijava.widget.InputPanel; +import org.scijava.widget.InputWidget; +import org.scijava.widget.WidgetModel; +import org.scijava.widget.WidgetService; + +/** + * Default implementation of {@link DialogService}. + * + * @author Christian Dietz, University of Konstanz + */ +@Plugin(type = DialogService.class) +public class DefaultDialogService extends AbstractService + implements DialogService { + + @Parameter + private WidgetService ws; + + @Parameter + private ModuleService ms; + + @Override + public Pair> dialogPanel( + final Module module) { + + final SwingInputHarvester builder = new SwingInputHarvester() { + @SuppressWarnings("unchecked") + @Override + public void buildPanel(final InputPanel inputPanel, + final Module module) throws ModuleException { + + // build input panel + super.buildPanel(inputPanel, module); + + // build output panel + // FIXME: Different Tab? + for (final ModuleItem item : module.getInfo().outputs()) { + final WidgetModel model = ws.createModel(inputPanel, module, + item, null); + inputPanel.addWidget( + (InputWidget) ws.create(model)); + } + + } + }; + builder.setContext(getContext()); + + final KNIMEInputPanel panel = new KNIMEInputPanel(); + try { + builder.buildPanel(panel, module); + } catch (final ModuleException e) { + // FIXME Error Handling / Logging + e.printStackTrace(); + } + + return new Pair>( + panel.getComponent(), panel.getWidgets()); + } + + @Override + public Pair> dialogPanel( + final ModuleInfo info) { + return dialogPanel(ms.createModule(info)); + } +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/dialog/DialogService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/dialog/DialogService.java new file mode 100644 index 0000000..fc5b5a2 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/dialog/DialogService.java @@ -0,0 +1,41 @@ +package org.knime.scijava.commands.dialog; + +import java.util.List; + +import javax.swing.JPanel; + +import org.knime.core.util.Pair; +import org.knime.scijava.commands.widget.SettingsModelWidgetModel; +import org.scijava.module.Module; +import org.scijava.module.ModuleInfo; +import org.scijava.service.SciJavaService; + +/** + * Interface for services which create dialog panels. + * + * @author Christian Dietz, University of Konstanz + */ +public interface DialogService extends SciJavaService { + + /** + * Create a dialog panel for the given module. + * + * @param module + * the module + * @return the created input panel and a list of + * {@link SettingsModelWidgetModel}s used for it. + */ + Pair> dialogPanel( + final Module module); + + /** + * Create a dialog panel for the given module info. + * + * @param info + * the module info + * @return the created input panel and a list of + * {@link SettingsModelWidgetModel}s used for it. + */ + Pair> dialogPanel( + final ModuleInfo info); +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/dialog/KNIMEInputPanel.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/dialog/KNIMEInputPanel.java new file mode 100644 index 0000000..6e88126 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/dialog/KNIMEInputPanel.java @@ -0,0 +1,37 @@ +package org.knime.scijava.commands.dialog; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JPanel; + +import org.knime.scijava.commands.widget.SettingsModelWidgetModel; +import org.scijava.ui.swing.widget.SwingInputPanel; +import org.scijava.widget.InputWidget; + +/** + * {@link SwingInputPanel} which allows retrieval of used + * {@link SettingsModelWidgetModel} models. + * + * @author Christian Dietz, University of Konstanz + */ +public class KNIMEInputPanel extends SwingInputPanel { + + /** + * Get a list of widget models used by this input panel. + * + * @return the list of {@link SettingsModelWidgetModel}s. + */ + public List getWidgets() { + final List models = new ArrayList(); + + for (final InputWidget widget : widgets.values()) { + final SettingsModelWidgetModel widgetModel = ((SettingsModelWidgetModel) widget + .get()); + models.add(widgetModel); + } + + return models; + } + +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/io/DefaultInputDataRowService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/io/DefaultInputDataRowService.java deleted file mode 100644 index e4b2872..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/io/DefaultInputDataRowService.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.knime.scijava.commands.io; - -import java.lang.ref.WeakReference; - -import org.knime.core.data.DataRow; -import org.knime.core.data.DataTableSpec; -import org.scijava.Priority; -import org.scijava.plugin.Plugin; -import org.scijava.service.AbstractService; - -/** - * Default implementation of InputDataRowService. Holds a {@link DataRow} and a - * {@link DataTableSpec} via a {@link WeakReference} to ensure that they can be - * garbage collected once they are not referenced outside this Service. - * - * @author Jonathan Hale (University of Konstanz) - */ -@Plugin(type = InputDataRowService.class, priority = DefaultInputDataRowService.PRIORITY) -public class DefaultInputDataRowService extends AbstractService - implements InputDataRowService { - - /** - * Priority of this {@link Plugin} - */ - public static final double PRIORITY = Priority.NORMAL_PRIORITY; - - private WeakReference m_row = new WeakReference<>(null); - private WeakReference m_spec = new WeakReference<>(null); - - /** - * {@inheritDoc} - */ - @Override - public DataRow getInputDataRow() { - return m_row.get(); - } - - /** - * Set the contained DataRow; - * - * @param dataRow - */ - @Override - public void setInputDataRow(final DataRow dataRow) { - m_row = new WeakReference<>(dataRow); - } - - @Override - public DataTableSpec getInputDataTableSpec() { - return m_spec.get(); - } - - @Override - public void setDataTableSpec(final DataTableSpec spec) { - m_spec = new WeakReference<>(spec); - } - -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/io/DefaultOutputDataRowService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/io/DefaultOutputDataRowService.java deleted file mode 100644 index 4f82175..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/io/DefaultOutputDataRowService.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.knime.scijava.commands.io; - -import java.lang.ref.WeakReference; -import java.util.List; - -import org.knime.core.data.DataCell; -import org.knime.core.data.DataRow; -import org.knime.core.data.RowKey; -import org.knime.core.data.def.DefaultRow; -import org.scijava.Priority; -import org.scijava.plugin.Plugin; -import org.scijava.service.AbstractService; - -/** - * Default implementation of OutputDataRowService. Holds a {@link WeakReference} - * to a {@link DataRow} to ensure that it can be garbage collected once the - * {@link DataRow} is not referenced outside of this service. - * - * @author Jonathan Hale (University of Konstanz) - * - */ -@Plugin(type = OutputDataRowService.class, priority = DefaultOutputDataRowService.PRIORITY) -public class DefaultOutputDataRowService extends AbstractService - implements OutputDataRowService { - - /** - * Priority of this {@link Plugin} - */ - public static final double PRIORITY = Priority.NORMAL_PRIORITY; - - private WeakReference> m_cells = new WeakReference<>(null); - - @Override - public void setOutputCells(final List cells) { - m_cells = new WeakReference<>(cells); - } - - @Override - public DataRow createOutputDataRow(final RowKey key) { - if (m_cells.get() == null) { - return null; - } - return new DefaultRow(key, m_cells.get()); - } - - @Override - public DataCell[] getOutputDataCells() { - if (m_cells.get() == null) { - return new DataCell[] {}; - } - - return m_cells.get().toArray(new DataCell[] {}); - } - - @Override - public void clear() { - m_cells = new WeakReference<>(null); - } - -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/io/InputDataRowService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/io/InputDataRowService.java deleted file mode 100644 index a108d59..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/io/InputDataRowService.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.knime.scijava.commands.io; - -import org.knime.core.data.DataRow; -import org.knime.core.data.DataTableSpec; -import org.scijava.plugin.Plugin; -import org.scijava.service.Service; - -/** - * Service holding a DataRow for input. - * - *

- * InputDataRowService plugins discoverable at runtime must implement this - * interface and be annotated with @{@link Plugin} with attribute - * {@link Plugin#type()} = {@link InputDataRowService}.class. - *

- * - * @author Jonathan Hale (University of Konstanz) - * @see OutputDataRowService - */ -public interface InputDataRowService extends Service { - - /** - * @return the contained DataRow. - */ - DataRow getInputDataRow(); - - /** - * @return the data table spec for the contained DataRow. - */ - DataTableSpec getInputDataTableSpec(); - - /** - * Set the input data row to hold. - */ - void setInputDataRow(DataRow row); - - /** - * Set the input table spec - * - * @param spec - */ - void setDataTableSpec(DataTableSpec spec); -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/io/OutputDataRowService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/io/OutputDataRowService.java deleted file mode 100644 index a91ee39..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/io/OutputDataRowService.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.knime.scijava.commands.io; - -import java.util.List; - -import org.knime.core.data.DataCell; -import org.knime.core.data.DataRow; -import org.knime.core.data.RowKey; -import org.scijava.module.Module; -import org.scijava.service.Service; - -/** - * Service holding a {@link DataCell}s output by a {@link Module}. - * - * @author Jonathan Hale (University of Konstanz) - * @see InputDataRowService - */ -public interface OutputDataRowService extends Service { - - /** - * Set the contained DataRow. - * - * @param r - * the Cells. - */ - void setOutputCells(List cells); - - /** - * @param key - * RowKey for the created row - * @return a DataRow from contained DataCells or null if no - * cells were set. - */ - DataRow createOutputDataRow(RowKey key); - - /** - * return a reference to the contained list of DataCells. - * - * @return the output {@link DataCell}s or an empty array if no cells were - * set. - */ - DataCell[] getOutputDataCells(); - - /** - * Clear the current contained DataCells. - */ - void clear(); - -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/log/KNIMELogService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/log/KNIMELogService.java new file mode 100644 index 0000000..e98d8da --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/log/KNIMELogService.java @@ -0,0 +1,164 @@ +package org.knime.scijava.commands.log; + +import org.knime.core.node.NodeLogger; +import org.scijava.Prioritized; +import org.scijava.Priority; +import org.scijava.log.LogService; +import org.scijava.service.AbstractService; + +/** + * Implementation of KNIMELogService to manually set to NodeModules to delegate + * logging from withing wrapped Scijava modules to KNIME. + * + * This class is not intededed to be instantiated by Scijava plugin managers but + * rather manually. + * + * @author Jonathan Hale, University of Konstanz + */ +public class KNIMELogService extends AbstractService implements LogService { + + public static final double PRIORITY = Priority.HIGH_PRIORITY; + + private final NodeLogger logger; + + /** + * Constructor. + * + * @param logger + * KNIME {@link NodeLogger} to delegate log to. + */ + public KNIMELogService(final NodeLogger logger) { + this.logger = logger; + } + + @Override + public int compareTo(final Prioritized o) { + return new Double(PRIORITY).compareTo(o.getPriority()); + } + + @Override + public LogService log() { + return this; + } + + @Override + public String getIdentifier() { + return getClass().getName(); + } + + @Override + public void debug(final Object msg) { + logger.debug(msg); + } + + @Override + public void debug(final Throwable t) { + logger.debug(t); + } + + @Override + public void debug(final Object msg, final Throwable t) { + logger.debug(msg, t); + } + + @Override + public void error(final Object msg) { + logger.error(msg); + } + + @Override + public void error(final Throwable t) { + logger.error(t); + } + + @Override + public void error(final Object msg, final Throwable t) { + logger.error(msg, t); + } + + @Override + public void info(final Object msg) { + logger.info(msg); + } + + @Override + public void info(final Throwable t) { + logger.info(t); + } + + @Override + public void info(final Object msg, final Throwable t) { + logger.info(msg, t); + } + + @Override + public void trace(final Object msg) { + // not supported + } + + @Override + public void trace(final Throwable t) { + // not supported + } + + @Override + public void trace(final Object msg, final Throwable t) { + // not supported + } + + @Override + public void warn(final Object msg) { + logger.warn(msg); + } + + @Override + public void warn(final Throwable t) { + logger.warn(t); + } + + @Override + public void warn(final Object msg, final Throwable t) { + logger.error(msg, t); + } + + @Override + public boolean isDebug() { + return logger.isDebugEnabled(); + } + + @Override + public boolean isError() { + return true; + } + + @Override + public boolean isInfo() { + return true; + } + + @Override + public boolean isTrace() { + return false; // not supported + } + + @Override + public boolean isWarn() { + return true; + } + + @Override + public int getLevel() { + return logger.getLevel().ordinal(); + } + + @Override + public void setLevel(final int level) { + // We do not want to allow Scijava commands to modify the node logger. + } + + @Override + public void setLevel(final String classOrPackageName, final int level) { + // We do not want to allow Scijava commands to modify the node logger. + } + +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/module/DefaultNodeModule.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/module/DefaultNodeModule.java new file mode 100644 index 0000000..c861e55 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/module/DefaultNodeModule.java @@ -0,0 +1,228 @@ +package org.knime.scijava.commands.module; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.knime.core.data.DataCell; +import org.knime.core.data.DataRow; +import org.knime.core.data.DataType; +import org.knime.core.node.ExecutionContext; +import org.knime.core.node.NodeLogger; +import org.knime.scijava.commands.CellOutput; +import org.knime.scijava.commands.MultiOutputListener; +import org.knime.scijava.commands.converter.KNIMEConverterService; +import org.knime.scijava.commands.log.KNIMELogService; +import org.scijava.Context; +import org.scijava.log.LogService; +import org.scijava.module.Module; +import org.scijava.module.ModuleInfo; +import org.scijava.module.ModuleItem; +import org.scijava.module.ModuleService; +import org.scijava.module.process.ModulePreprocessor; +import org.scijava.module.process.PreprocessorPlugin; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.PluginService; +import org.scijava.script.ScriptInfo; + +/** + * Default implementation of {@link NodeModule}. + * + * @author Christian Dietz, University of Konstanz + */ +class DefaultNodeModule implements NodeModule { + + @Parameter + private PluginService ps; + + @Parameter + private KNIMEConverterService cs; + + @Parameter + private ModuleService ms; + + // Internally used variables + private final Module module; + + private final Map> inputMapping; + + private final Map, DataType> outputMapping; + + private NodeModuleOutputChangedListener outputListener; + + private final LogService logService; + + /** + * Constructor. + * + * @param context + * Scijava context. + * @param info + * info this module is created for + * @param params + * preresolved values for the parameters of the module + * @param inputMapping + * mapping of input column index to input items of the module + * @param outputMapping + * mapping of output items to types for the cells to for them + * @param logger + * NodeLogger to delegate output to. + */ + public DefaultNodeModule(final Context context, final ModuleInfo info, + final Map params, + final Map> inputMapping, + final Map, DataType> outputMapping, + final NodeLogger logger) { + context.inject(this); + + this.inputMapping = inputMapping; + this.outputMapping = outputMapping; + this.module = ms.createModule(info); + this.outputListener = new NodeModuleOutputChangedListener(false); + this.logService = new KNIMELogService(logger); + + preProcess(params); + } + + /* + * "Once per node execution" pre-processing. Called in constructor. + * + * @param params key-value pairs of pre resolved module inputs. + */ + private void preProcess(final Map params) { + // Setting parameters + for (final Entry entry : params.entrySet()) { + module.setInput(entry.getKey(), entry.getValue()); + module.resolveInput(entry.getKey()); + } + + // FIXME: do we need them all? + final List pre = ps + .createInstancesOfType(PreprocessorPlugin.class); + + for (final ModulePreprocessor p : pre) { + p.process(module); + } + + for (final ModuleItem item : this.module.getInfo().inputs()) { + if (MultiOutputListener.class.equals(item.getType())) { + /* MultiOutputListener */ + final String name = item.getName(); + + outputListener = new NodeModuleOutputChangedListener(true); + module.setInput(name, outputListener); + module.resolveInput(name); + } else if (LogService.class.equals(item.getType())) { + /* LogService */ + final String name = item.getName(); + + module.setInput(name, logService); + module.resolveInput(name); + } + } + } + + /* + * Set module input values from the input row. + */ + private void setModuleInput(final DataRow input) throws Exception { + // input can be null if source node + if (input != null) { + for (final Entry> entry : inputMapping + .entrySet()) { + final Object obj = cs.convertToJava( + input.getCell(entry.getKey()), + entry.getValue().getType()); + module.setInput(entry.getValue().getName(), obj); + } + } + } + + @Override + public void run(final DataRow input, final CellOutput output, + final ExecutionContext ctx) throws Exception { + setModuleInput(input); + + outputListener.setCellOutput(output); + outputListener.setExecutionContext(ctx); + + module.run(); + + outputListener.flush(); + } + + private class NodeModuleOutputChangedListener + implements MultiOutputListener { + private ExecutionContext ctx; + + private CellOutput output; + + /* true if the modules handles pushes itself, false otherwise */ + private final boolean manualPush; + + /** + * Constructor. + * + * @param manualPush + * if true, signals that the module handles + * pushing rows. + */ + public NodeModuleOutputChangedListener(final boolean manualPush) { + this.manualPush = manualPush; + } + + @Override + public void notifyListener() throws Exception { + // output can be null if sink node + if (output != null) { + final boolean hasSyntheticResult = module.getInfo() instanceof ScriptInfo && + ((ScriptInfo) module.getInfo()).isReturnValueAppended(); + + final List cells = new ArrayList(); + for (final ModuleItem entry : module.getInfo().outputs()) { + // FIXME hack because e.g. python script contains + // result log + if (!hasSyntheticResult || !entry.getName().equals("result")) { + cells.add(cs.convertToKnime( + module.getOutput(entry.getName()), + entry.getType(), outputMapping.get(entry), + ctx)); + } + } + output.push(cells.toArray(new DataCell[cells.size()])); + } + } + + /** + * Set KNIME Execution Context + * + * @param ctx + * execution context + */ + public void setExecutionContext(final ExecutionContext ctx) { + this.ctx = ctx; + } + + /** + * Set CellOutput to push rows to. + * + * @param output + * cell output + */ + public void setCellOutput(final CellOutput output) { + this.output = output; + } + + /** + * Final flush. Will push a row in case module does not handle pushing + * output rows. + * @throws Exception + */ + public void flush() throws Exception { + if (!manualPush) { + notifyListener(); + } + } + } +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/module/DefaultNodeModuleService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/module/DefaultNodeModuleService.java new file mode 100644 index 0000000..b244d69 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/module/DefaultNodeModuleService.java @@ -0,0 +1,170 @@ +package org.knime.scijava.commands.module; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.knime.core.data.DataColumnSpec; +import org.knime.core.data.DataTableSpec; +import org.knime.core.data.DataType; +import org.knime.core.node.NodeLogger; +import org.knime.core.node.defaultnodesettings.SettingsModel; +import org.knime.core.util.UniqueNameGenerator; +import org.knime.scijava.commands.MultiOutputListener; +import org.knime.scijava.commands.converter.KNIMEConverterService; +import org.knime.scijava.commands.settings.SettingsModelType; +import org.knime.scijava.commands.settings.SettingsModelTypeService; +import org.knime.scijava.commands.settings.models.SettingsModelColumnSelection; +import org.knime.scijava.commands.settings.types.SettingsModelColumnSelectionType; +import org.scijava.Identifiable; +import org.scijava.module.ModuleInfo; +import org.scijava.module.ModuleItem; +import org.scijava.module.ModuleService; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; +import org.scijava.script.ScriptInfo; +import org.scijava.service.AbstractService; + +/** + * Default implementation of {@link NodeModuleService}. + * + * @author Christian Dietz, University of Konstanz + */ +@Plugin(type = NodeModuleService.class) +public class DefaultNodeModuleService extends AbstractService + implements NodeModuleService { + + @Parameter + private SettingsModelTypeService ts; + + @Parameter + private KNIMEConverterService cs; + + @Parameter + private ModuleService ms; + + @Override + public NodeModule createNodeModule(final ModuleInfo info, + final Map models, final DataTableSpec spec, + final NodeLogger knimeLogger) { + + final Map> inputMapping = new HashMap<>(); + final Map params = new HashMap(); + + final Map, DataType> outputMapping = getOutputMapping( + info, models); + for (final ModuleItem item : info.inputs()) { + if (MultiOutputListener.class.isAssignableFrom(item.getType())) { + continue; + } + + final String name = item.getName(); + + final SettingsModelType type = ts + .getSettingsModelTypeFor(item); + + // FIXME make this extensible? special handling for special + // mappings or SettingsModels? + if (type instanceof SettingsModelColumnSelectionType) { + final SettingsModelColumnSelection settingsModel = (SettingsModelColumnSelection) models + .get(item.getName()); + inputMapping.put( + spec.findColumnIndex(settingsModel.getStringValue()), + item); + } else { + @SuppressWarnings("unchecked") + final SettingsModelType tmp = ((SettingsModelType) type); + params.put(name, tmp.getValue(models.get(name))); + } + } + + return new DefaultNodeModule(getContext(), info, params, inputMapping, + outputMapping, knimeLogger); + + } + + @Override + public DataTableSpec createOutSpec(final ModuleInfo info, + final Map models, + final DataTableSpec inSpec) { + + final Map, DataType> outputMapping = getOutputMapping( + info, models); + + final UniqueNameGenerator nameGen; + if (inSpec != null) { + nameGen = new UniqueNameGenerator(inSpec); + } else { + nameGen = new UniqueNameGenerator(new HashSet<>()); + } + + final List tableSpecs = new ArrayList<>(); + + final boolean hasSyntheticResult = info instanceof ScriptInfo && + ((ScriptInfo) info).isReturnValueAppended(); + for (final ModuleItem item : info.outputs()) { + if (!hasSyntheticResult && item.getName().equals("result")) { + continue; + } + tableSpecs.add( + nameGen.newColumn(item.getName(), outputMapping.get(item))); + } + + return new DataTableSpec( + tableSpecs.toArray(new DataColumnSpec[tableSpecs.size()])); + } + + @Override + public Map, DataType> getOutputMapping(final ModuleInfo info, + final Map models) { + final HashMap, DataType> outputMapping = new HashMap<>(); + + for (final ModuleItem item : info.outputs()) { + final Optional type = cs + .getPreferredDataType(item.getType()); + + if (type.isPresent()) { + final DataType theType = type.get(); + outputMapping.put(item, theType); + } + } + + return outputMapping; + } + + @Override + public boolean hasMultiOutputListener(final ModuleInfo info) { + for (final ModuleItem item : info.inputs()) { + if (MultiOutputListener.class.isAssignableFrom(item.getType())) { + return true; + } + } + + return false; + } + + @Override + public String getModuleInfoId(final ModuleInfo info) { + + if (info instanceof Identifiable) { + return ((Identifiable) info).getIdentifier(); + } + + throw new IllegalStateException( + "Only Identifiable ModuleInfos are supported, yet!"); + + } + + @Override + public ModuleInfo getModuleInfoFromId(final String id) { + final ModuleInfo info = ms.getModuleById(id); + if (info != null) { + return info; + } + throw new IllegalStateException( + "Only Identifiable ModuleInfos are supported, yet!"); + } +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/module/NodeModule.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/module/NodeModule.java new file mode 100644 index 0000000..9ae1cb8 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/module/NodeModule.java @@ -0,0 +1,29 @@ +package org.knime.scijava.commands.module; + +import org.knime.core.data.DataRow; +import org.knime.core.node.ExecutionContext; +import org.knime.scijava.commands.CellOutput; + +/** + * Interface for NodeModules, wrappers around ModuleInfo which can be executed + * by KNIME. + * + * @author Christian Dietz, University of Konstanz + */ +public interface NodeModule { + + /** + * Run the module on a {@link DataRow}. + * + * @param input + * the {@link DataRow}. + * @param output + * Where to push output to. + * @param ctx + * KNIME {@link ExecutionContext}. + * @throws Exception + * If an exception occurs while executing the module. + */ + void run(final DataRow input, final CellOutput output, + final ExecutionContext ctx) throws Exception; +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/module/NodeModuleService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/module/NodeModuleService.java new file mode 100644 index 0000000..b20b720 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/module/NodeModuleService.java @@ -0,0 +1,92 @@ +package org.knime.scijava.commands.module; + +import java.util.Map; + +import org.knime.core.data.DataTableSpec; +import org.knime.core.data.DataType; +import org.knime.core.node.NodeLogger; +import org.knime.core.node.defaultnodesettings.SettingsModel; +import org.scijava.module.ModuleInfo; +import org.scijava.module.ModuleItem; +import org.scijava.service.SciJavaService; + +/** + * Interface for services which are able to create {@link DataTableSpec}s from + * ModuleInfos and is able to create NodeModules. + * + * @author Christian Dietz, University of Konstanz + */ +public interface NodeModuleService extends SciJavaService { + + /** + * Create a output {@link DataTableSpec} from a {@link ModuleInfo}. + * + * @param info + * module info to create {@link DataTableSpec} from. + * @param models + * {@link SettingsModel}s for given info. + * @param inSpec + * Input {@link DataTableSpec}. + * @return the created spec. + */ + DataTableSpec createOutSpec(final ModuleInfo info, + final Map models, + final DataTableSpec inSpec); + + /** + * Get the current output {@link ModuleItem} to {@link DataType} mapping. + * + * @param info + * The module info to get the output mapping for. + * @param models + * {@link SettingsModel}s for given info. + * @return A Map of the module items and the respective {@link DataType} of + * the output column to which they should be mapped. + */ + Map, DataType> getOutputMapping(final ModuleInfo info, + final Map models); + + /** + * Create a NodeModule from the module info, a executable wrapper around the + * module info for KNIME. + * + * @param info + * the module info to create a NodeModule for. + * @param models + * settings models for {@link ModuleItem}s in info + * @param spec + * Input data table spec + * @param knimeLogger + * KNIME {@link NodeLogger} to delegate output to. + * @return the {@link NodeModule} + */ + NodeModule createNodeModule(final ModuleInfo info, + final Map models, final DataTableSpec spec, + NodeLogger knimeLogger); + + /** + * @param info + * the module info + * @return Whether the given Module info has a MultiOutputListener + */ + boolean hasMultiOutputListener(final ModuleInfo info); + + /** + * Get an id for the {@link ModuleInfo}. + * + * @param info + * the module info + * @return the id + */ + String getModuleInfoId(final ModuleInfo info); + + /** + * Get the module info for the given id. + * + * @param id + * the id + * @return the module info or null if the id was invalid + */ + ModuleInfo getModuleInfoFromId(final String id); + +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/KeyGenerator.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/KeyGenerator.java new file mode 100644 index 0000000..4ad2538 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/KeyGenerator.java @@ -0,0 +1,28 @@ +package org.knime.scijava.commands.nodes; + +import org.knime.core.data.RowKey; + +/** + * Interface for classes able to create {@link RowKey}s. + * + * @author Christian Dietz, University of Konstanz + */ +public interface KeyGenerator { + + /** + * Create a new {@link RowKey}. + * + * @return the created {@link RowKey} + */ + public RowKey create(); + + /** + * Set current key. All following calls to {@link #create()} create keys + * sequential to the current key. + * + * @param curr + * current row key + */ + public void setCurrentKey(final RowKey curr); + +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaCommandNodeDialog.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaCommandNodeDialog.java new file mode 100644 index 0000000..c9d750e --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaCommandNodeDialog.java @@ -0,0 +1,75 @@ +package org.knime.scijava.commands.nodes; + +import java.util.List; + +import javax.swing.JPanel; + +import org.knime.core.data.DataTableSpec; +import org.knime.core.node.InvalidSettingsException; +import org.knime.core.node.NodeDialogPane; +import org.knime.core.node.NodeSettingsRO; +import org.knime.core.node.NodeSettingsWO; +import org.knime.core.node.NotConfigurableException; +import org.knime.core.node.defaultnodesettings.SettingsModel; +import org.knime.core.util.Pair; +import org.knime.scijava.commands.dialog.DialogService; +import org.knime.scijava.commands.settings.models.SettingsModelColumnSelection; +import org.knime.scijava.commands.widget.SettingsModelWidgetModel; +import org.scijava.Context; +import org.scijava.module.ModuleInfo; +import org.scijava.plugin.Parameter; + +/** + * Dialog for the Scripting Node. + * + * @author Jonathan Hale + * @author Christian Dietz + * + * @see SciJavaScriptingNodeModel + * @see SciJavaScriptingNodeFactory + */ +public class SciJavaCommandNodeDialog extends NodeDialogPane { + + @Parameter + private DialogService ds; + + private final List settingsModels; + + public SciJavaCommandNodeDialog(final Context ctx, final ModuleInfo info) { + ctx.inject(this); + final Pair> dialog = ds + .dialogPanel(info); + addTab("Configure", dialog.getFirst()); + settingsModels = dialog.getSecond(); + } + + @Override + protected void saveSettingsTo(final NodeSettingsWO settings) + throws InvalidSettingsException { + for (final SettingsModelWidgetModel model : settingsModels) { + model.getSettingsModel().saveSettingsTo(settings); + } + } + + @Override + protected void loadSettingsFrom(final NodeSettingsRO settings, + final DataTableSpec[] specs) throws NotConfigurableException { + + try { + for (final SettingsModelWidgetModel widget : settingsModels) { + final SettingsModel model = widget.getSettingsModel(); + model.loadSettingsFrom(settings); + + if (model instanceof SettingsModelColumnSelection) { + ((SettingsModelColumnSelection) model).setSpec(specs[0]); + + } + widget.getPanel().refresh(); + } + + } catch (final InvalidSettingsException e) { + throw new NotConfigurableException("Can't create dialog : " + e); + } + } + +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaCommandNodeFactory.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaCommandNodeFactory.java new file mode 100644 index 0000000..fc2ff2c --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaCommandNodeFactory.java @@ -0,0 +1,137 @@ +package org.knime.scijava.commands.nodes; + +import java.util.Map; +import java.util.Map.Entry; + +import org.knime.core.node.DynamicNodeFactory; +import org.knime.core.node.InvalidSettingsException; +import org.knime.core.node.NodeDescription; +import org.knime.core.node.NodeDialogPane; +import org.knime.core.node.NodeView; +import org.knime.core.node.config.ConfigRO; +import org.knime.core.node.config.ConfigWO; +import org.knime.core.node.defaultnodesettings.SettingsModel; +import org.knime.scijava.commands.SciJavaGateway; +import org.knime.scijava.commands.module.NodeModuleService; +import org.knime.scijava.commands.settings.NodeSettingsService; +import org.knime.scijava.commands.settings.models.SettingsModelColumnSelection; +import org.scijava.module.ModuleInfo; +import org.scijava.plugin.Parameter; + +/** + * NodeModel of Scijava Command Nodes. + * + * @author Christian Dietz, University of Konstanz + */ +// FIXME Make abstract in the long run? +public class SciJavaCommandNodeFactory + extends DynamicNodeFactory { + + @Parameter + private NodeSettingsService nss; + + @Parameter + private NodeModuleService nms; + + private ModuleInfo info; + + private Map models; + + private int numOutports; + + private int numInports; + + public SciJavaCommandNodeFactory() { + super(); + SciJavaGateway.get().getGlobalContext().inject(this); + } + + @Override + protected NodeDescription createNodeDescription() { + return new SciJavaNodeDescription(info, numInports, numOutports); + } + + /** + * {@inheritDoc} + */ + @Override + protected int getNrNodeViews() { + // FIXME + return 0; + } + + /** + * {@inheritDoc} + * + * @return null (ScriptingNode does not have views.) + */ + @Override + public NodeView createNodeView(final int viewIndex, + final SciJavaCommandNodeModel nodeModel) { + // FIXME + return null; + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean hasDialog() { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + protected NodeDialogPane createNodeDialogPane() { + return new SciJavaCommandNodeDialog( + SciJavaGateway.get().getGlobalContext(), info); + } + + @Override + public void saveAdditionalFactorySettings(final ConfigWO config) { + config.addString(SciJavaNodeSetFactory.SCIJAVA_COMMAND_KEY, + nms.getModuleInfoId(info)); + super.saveAdditionalFactorySettings(config); + } + + @Override + public void loadAdditionalFactorySettings(final ConfigRO config) + throws InvalidSettingsException { + info = nms.getModuleInfoFromId( + config.getString(SciJavaNodeSetFactory.SCIJAVA_COMMAND_KEY)); + models = nss.getSettingsModels(info); + numInports = getNrInPorts(info, models); + numOutports = getNrOutPorts(info); + + // FIXME numViews etc.. + + super.loadAdditionalFactorySettings(config); + } + + /** + * {@inheritDoc} + */ + @Override + public SciJavaCommandNodeModel createNodeModel() { + return new SciJavaCommandNodeModel( + SciJavaGateway.get().getGlobalContext(), info, models, + numInports, numOutports); + } + + private static int getNrOutPorts(final ModuleInfo info) { + return info.outputs().iterator().hasNext() ? 1 : 0; + } + + private static int getNrInPorts(final ModuleInfo info, + final Map map) { + for (final Entry model : map.entrySet()) { + if (model.getValue() instanceof SettingsModelColumnSelection) { + return 1; + } + } + return 0; + } + +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaCommandNodeModel.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaCommandNodeModel.java new file mode 100644 index 0000000..82c99b6 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaCommandNodeModel.java @@ -0,0 +1,274 @@ +package org.knime.scijava.commands.nodes; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import org.knime.core.data.DataCell; +import org.knime.core.data.DataRow; +import org.knime.core.data.DataTableSpec; +import org.knime.core.data.RowKey; +import org.knime.core.data.def.DefaultRow; +import org.knime.core.node.BufferedDataTable; +import org.knime.core.node.CanceledExecutionException; +import org.knime.core.node.ExecutionContext; +import org.knime.core.node.ExecutionMonitor; +import org.knime.core.node.InvalidSettingsException; +import org.knime.core.node.NodeLogger; +import org.knime.core.node.NodeModel; +import org.knime.core.node.NodeSettingsRO; +import org.knime.core.node.NodeSettingsWO; +import org.knime.core.node.defaultnodesettings.SettingsModel; +import org.knime.core.node.port.PortObjectSpec; +import org.knime.core.node.streamable.BufferedDataTableRowOutput; +import org.knime.core.node.streamable.DataTableRowInput; +import org.knime.core.node.streamable.InputPortRole; +import org.knime.core.node.streamable.OutputPortRole; +import org.knime.core.node.streamable.PartitionInfo; +import org.knime.core.node.streamable.PortInput; +import org.knime.core.node.streamable.PortOutput; +import org.knime.core.node.streamable.RowInput; +import org.knime.core.node.streamable.RowOutput; +import org.knime.core.node.streamable.StreamableOperator; +import org.knime.scijava.commands.CellOutput; +import org.knime.scijava.commands.module.NodeModule; +import org.knime.scijava.commands.module.NodeModuleService; +import org.scijava.Context; +import org.scijava.module.ModuleInfo; +import org.scijava.plugin.Parameter; + +/** + * NodeModel of ScijavaCommandNodes. + * + * @author Christian Dietz, University of Konstanz + * @see SciJavaNodeSetFactory + */ +public class SciJavaCommandNodeModel extends NodeModel { + + @Parameter + private NodeModuleService nodeService; + + private final ModuleInfo info; + + private final Map models; + + private Context context; + + private final NodeLogger logger; + + protected SciJavaCommandNodeModel(final Context ctx, final ModuleInfo info, + final Map models, final int numInports, + final int numOutports) { + super(numInports, numOutports); + setContext(ctx); + this.info = info; + this.models = models; + + logger = NodeLogger.getLogger(info.getName()); + } + + private void setContext(final Context ctx) { + this.context = ctx; + context.inject(this); + } + + @Override + protected DataTableSpec[] configure(final DataTableSpec[] inSpecs) + throws InvalidSettingsException { + if (getNrOutPorts() == 0) { + return null; + } else { + return new DataTableSpec[] { nodeService.createOutSpec(info, models, + getNrInPorts() == 0 ? null : inSpecs[0]) }; + } + } + + @Override + protected BufferedDataTable[] execute(final BufferedDataTable[] inData, + final ExecutionContext exec) throws Exception { + + final DataTableSpec inSpec = getNrInPorts() == 0 ? null + : inData[0].getSpec(); + + final BufferedDataTableRowOutput rowOutput; + if (getNrOutPorts() != 0) { + rowOutput = new BufferedDataTableRowOutput(exec.createDataContainer( + nodeService.createOutSpec(info, models, inSpec))); + } else { + rowOutput = null; + } + + run(inSpec, + getNrInPorts() == 0 ? null : new DataTableRowInput(inData[0]), + rowOutput, exec, inData.length > 0 ? inData[0].size() : -1); + + rowOutput.close(); + + return new BufferedDataTable[] { rowOutput.getDataTable() }; + } + + private void run(final DataTableSpec spec, final RowInput rowInput, + final RowOutput rowOutput, final ExecutionContext exec, + final long totalRows) { + try { + + final KeyGenerator keyGen = createKeyGenerator(rowInput, rowOutput); + + final NodeModule module = nodeService.createNodeModule(info, models, + spec, logger); + + CellOutput output = null; + if (getNrOutPorts() > 0) { + output = new CellOutput() { + + @Override + public void push(final DataCell[] cells) + throws InterruptedException { + rowOutput.push(new DefaultRow(keyGen.create(), cells)); + } + }; + } + + if (rowInput != null) { + DataRow input; + float ctr = 0; + while ((input = rowInput.poll()) != null) { + keyGen.setCurrentKey(input.getKey()); + module.run(input, output, exec); + exec.setProgress(ctr++ / totalRows); + exec.checkCanceled(); + } + } else { + module.run(null, output, exec); + } + } catch (final Exception e) { + e.printStackTrace(); + } + + } + + private KeyGenerator createKeyGenerator(final RowInput rowInput, + final RowOutput rowOutput) { + if (nodeService.hasMultiOutputListener(info)) { + return new KeyGenerator() { + private RowKey curr; + private long ctr = 0; + + @Override + public RowKey create() { + if (curr == null) { + return RowKey.createRowKey(ctr++); + } else { + return new RowKey(curr.getString() + "#" + ctr++); + } + } + + @Override + public void setCurrentKey(final RowKey curr) { + this.curr = curr; + } + }; + } else { + return new KeyGenerator() { + private RowKey curr; + private long ctr = 0; + + @Override + public RowKey create() { + if (curr == null) { + return RowKey.createRowKey(ctr++); + } else { + return new RowKey(curr.getString()); + } + } + + @Override + public void setCurrentKey(final RowKey curr) { + this.curr = curr; + } + }; + } + } + + @Override + protected void validateSettings(final NodeSettingsRO settings) + throws InvalidSettingsException { + for (final SettingsModel model : models.values()) { + model.validateSettings(settings); + } + } + + @Override + protected void loadValidatedSettingsFrom(final NodeSettingsRO settings) + throws InvalidSettingsException { + for (final SettingsModel model : models.values()) { + model.loadSettingsFrom(settings); + } + } + + @Override + protected void saveSettingsTo(final NodeSettingsWO settings) { + for (final SettingsModel model : models.values()) { + model.saveSettingsTo(settings); + } + } + + // Streaming + @Override + public InputPortRole[] getInputPortRoles() { + if (getNrInPorts() == 1) { + return new InputPortRole[] { InputPortRole.DISTRIBUTED_STREAMABLE }; + } else { + return new InputPortRole[0]; + } + } + + @Override + public OutputPortRole[] getOutputPortRoles() { + if (getNrOutPorts() == 1) { + return new OutputPortRole[] { OutputPortRole.DISTRIBUTED }; + } else { + return new OutputPortRole[0]; + } + } + + // FIXME must be super performant + @Override + public StreamableOperator createStreamableOperator( + final PartitionInfo partitionInfo, final PortObjectSpec[] inSpecs) + throws InvalidSettingsException { + return new StreamableOperator() { + + @Override + public void runFinal(final PortInput[] inputs, + final PortOutput[] outputs, final ExecutionContext exec) + throws Exception { + // FIXME avoid recreation of module in each run + run((DataTableSpec) inSpecs[0], + getNrInPorts() == 0 ? null : (RowInput) inputs[0], + (RowOutput) outputs[0], exec, -1); + } + }; + } + + @Override + protected void reset() { + /* nothing to do */ + } + + // --- loading and saving --- + @Override + protected void loadInternals(final File nodeInternDir, + final ExecutionMonitor exec) + throws IOException, CanceledExecutionException { + /* nothing to do */ + } + + @Override + protected void saveInternals(final File nodeInternDir, + final ExecutionMonitor exec) + throws IOException, CanceledExecutionException { + /* nothing to do */ + } + +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaNodeDescription.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaNodeDescription.java new file mode 100644 index 0000000..efcbd66 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaNodeDescription.java @@ -0,0 +1,98 @@ +package org.knime.scijava.commands.nodes; + +import org.knime.core.node.NodeDescription; +import org.knime.core.node.NodeFactory.NodeType; +import org.scijava.Identifiable; +import org.scijava.module.ModuleInfo; +import org.w3c.dom.Element; + +/** + * Dynamic NodeDescription for SciJavaNodeSetFactory nodes. + * + * @author Christian Dietz, University of Konstanz + */ +// FIXME ;-) +// FIXME maybe abstract? +public class SciJavaNodeDescription extends NodeDescription { + + private final ModuleInfo info; + private final NodeType nodeType; + + public SciJavaNodeDescription(final ModuleInfo info, final int numInports, + final int numOutports) { + this.info = info; + this.nodeType = numInports > 0 && numOutports > 0 ? NodeType.Manipulator + : (numInports == 0 ? NodeType.Sink : NodeType.Source); + } + + @Override + public String getIconPath() { + return info.getIconPath(); + } + + @Override + public String getInportDescription(final int index) { + // FIXME + return "Inport Info"; + } + + @Override + public String getInportName(final int index) { + // FIXME + return "Inport name"; + } + + @Override + public String getInteractiveViewName() { + // FIXME will be used by imagej2 integration + return null; + } + + @Override + public String getNodeName() { + return info.getLabel() != null ? info.getLabel() + : ((Identifiable) info).getIdentifier(); + } + + @Override + public String getOutportDescription(final int index) { + // FIXME + return "Outport desc"; + } + + @Override + public String getOutportName(final int index) { + // FIXME + return "Outport name"; + } + + @Override + public NodeType getType() { + return nodeType; + } + + @Override + public int getViewCount() { + // FIXME will be used by ImageJ integration + return 0; + } + + @Override + public String getViewDescription(final int index) { + // FIXME + return null; + } + + @Override + public String getViewName(final int index) { + // FIXME + return null; + } + + @Override + public Element getXMLDescription() { + // FIXME will comprise all input and output parameters etc + return null; + } + +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaNodeSetFactory.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaNodeSetFactory.java new file mode 100644 index 0000000..b463c10 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaNodeSetFactory.java @@ -0,0 +1,123 @@ +package org.knime.scijava.commands.nodes; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + +import org.knime.core.node.NodeFactory; +import org.knime.core.node.NodeModel; +import org.knime.core.node.NodeSetFactory; +import org.knime.core.node.NodeSettings; +import org.knime.core.node.config.ConfigRO; +import org.knime.scijava.commands.SciJavaGateway; +import org.knime.scijava.commands.SciJavaTestCommand; +import org.knime.scijava.commands.module.NodeModuleService; +import org.scijava.MenuEntry; +import org.scijava.MenuPath; +import org.scijava.command.CommandService; +import org.scijava.module.ModuleInfo; +import org.scijava.plugin.Parameter; +import org.scijava.script.ScriptService; + +/** + * NodeSetFactory which creates Nodes for Scijava commands. + * + * @author Christian Dietz, University of Konstanz + */ +// FIXME Temporarily. Serves as an example. Maybe abstract in the future +public class SciJavaNodeSetFactory implements NodeSetFactory { + + public static final String SCIJAVA_COMMAND_KEY = "SCIJAVA_COMMAND_KEY"; + + private static final String SCIJAVA_TEST_PATH = "/community/knip/scijava"; + + // FIXME this is temporary. Will be moved to specialized NodeSetFactory + @Parameter + private ScriptService scripts; + + // FIXME this is temporary. Will be moved to specialized NodeSetFactory. + @Parameter + private CommandService cs; + + @Parameter + private NodeModuleService nms; + + public SciJavaNodeSetFactory() { + SciJavaGateway.get().getGlobalContext().inject(this); + } + + private final HashMap categories = new HashMap(); + + /* + * Scan script directory for scripts and add test command + */ + private List discoverModules() { + final List infos = new ArrayList<>(); + + // FIXME this hack should take place in the activator of the potential + // new scripting plugin + final ClassLoader curr = Thread.currentThread().getContextClassLoader(); + Thread.currentThread() + .setContextClassLoader(SciJavaGateway.get().getClassLoader()); + scripts.addScriptDirectory(new File("/home/dietzc/Desktop/scripts/"), + new MenuPath("SciJava>Test")); + + infos.addAll(scripts.getScripts()); + infos.add(cs.getCommand(SciJavaTestCommand.class)); + + Thread.currentThread().setContextClassLoader(curr); + + return infos; + } + + @Override + public Collection getNodeFactoryIds() { + final List moduleInfos = discoverModules(); + final List moduleIds = new ArrayList( + moduleInfos.size()); + for (final ModuleInfo info : moduleInfos) { + final String id = nms.getModuleInfoId(info); + moduleIds.add(id); + + String path = ""; + if (info.getMenuPath().size() > 0) { + String tmp = ""; + for (final MenuEntry entry : info.getMenuPath()) { + path += tmp; // omit last value from the menu + tmp = "/" + entry.getName(); + } + } + categories.put(id, SCIJAVA_TEST_PATH + path); + } + + return moduleIds; + } + + @Override + public Class> getNodeFactory( + final String id) { + return SciJavaCommandNodeFactory.class; + } + + @Override + public String getCategoryPath(final String id) { + return categories.get(id); + } + + @Override + public String getAfterID(final String id) { + return ""; + } + + @Override + public ConfigRO getAdditionalSettings(final String id) { + // FIXME manage versions? + final NodeSettings settings = new NodeSettings( + "scijavacommand-factory"); + settings.addString(SCIJAVA_COMMAND_KEY, id); + return settings; + } + +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaTestNodeFactory.xml b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaTestNodeFactory.xml new file mode 100644 index 0000000..07811bf --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/SciJavaTestNodeFactory.xml @@ -0,0 +1,22 @@ + + + + SciJava Test + + + + + + + + + + + Data table to input to the script. + + + Output of the script as a table. + + + + diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/icon.png b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/icon.png new file mode 100644 index 0000000..bbc21e3 Binary files /dev/null and b/org.knime.scijava.commands/src/org/knime/scijava/commands/nodes/icon.png differ diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/process/DefaultKnimePostprocessor.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/process/DefaultKnimePostprocessor.java deleted file mode 100644 index 46e8b30..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/process/DefaultKnimePostprocessor.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.knime.scijava.commands.process; - -import java.util.ArrayList; -import java.util.List; - -import org.knime.core.data.DataCell; -import org.knime.scijava.commands.converter.ConverterCacheService; -import org.knime.scijava.commands.io.OutputDataRowService; -import org.scijava.Priority; -import org.scijava.log.LogService; -import org.scijava.module.Module; -import org.scijava.module.ModuleItem; -import org.scijava.module.process.AbstractPostprocessorPlugin; -import org.scijava.module.process.PostprocessorPlugin; -import org.scijava.plugin.Parameter; -import org.scijava.plugin.Plugin; - -/** - * Default implementation of KnimePostprocessor. - * - * @author Jonathan Hale (University of Konstanz) - * - */ -@Plugin(type = PostprocessorPlugin.class, priority = Priority.NORMAL_PRIORITY) -public class DefaultKnimePostprocessor extends AbstractPostprocessorPlugin - implements KnimePostprocessor { - - @Parameter - private ConverterCacheService m_converters; - - @Parameter - private OutputDataRowService m_dataRowOut; - - @Parameter - private LogService m_log; - - /** - * Straight forward implementation of module output to DataRow: For every - * output find an OutputAdapter to create a DataCell from it and create a - * DefaultDataRow from created DataCells. - * - * {@inheritDoc} - */ - @SuppressWarnings({ "rawtypes" }) - @Override - public void process(final Module module) { - - final List cells = new ArrayList<>( - module.getOutputs().size()); - - for (final ModuleItem i : module.getInfo().outputs()) { - - // FIXME Ugly hack! - if (i.getName().equals("result")) { - continue; - } - - DataCell out = null; - try { - out = m_converters.convertToKnime(module.getOutput(i.getName()), - i.getType()); - } catch (final Exception e) { - throw new IllegalArgumentException(e); - } - cells.add(out); - } - - m_dataRowOut.setOutputCells(cells); - } -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/process/KnimePostprocessor.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/process/KnimePostprocessor.java deleted file mode 100644 index e50d5a2..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/process/KnimePostprocessor.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.knime.scijava.commands.process; - -import org.knime.core.data.DataRow; -import org.scijava.module.process.PostprocessorPlugin; -import org.scijava.plugin.Plugin; - -/** - * Creates a {@link DataRow} from output of a module after its execution. - * - *

- * KnimePostprocessor plugins discoverable at runtime must implement this - * interface and be annotated with @{@link Plugin} with attribute - * {@link Plugin#type()} = {@link KnimePostprocessor}.class. - *

- * - * @author Jonathan Hale (University of Konstanz) - */ -public interface KnimePostprocessor extends PostprocessorPlugin { - // Marker interface -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/process/KnimePreprocessor.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/process/KnimePreprocessor.java deleted file mode 100644 index c3da043..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/process/KnimePreprocessor.java +++ /dev/null @@ -1,20 +0,0 @@ - -package org.knime.scijava.commands.process; - -import org.scijava.module.process.PreprocessorPlugin; -import org.scijava.plugin.Plugin; - -/** - * A preprocessor that handles unresolved parameters of various types using a - * {@link KNIMEInputDataTableService}. - *

- * KnimePreprocessor plugins discoverable at runtime must implement this - * interface and be annotated with @{@link Plugin} with attribute - * {@link Plugin#type()} = {@link KnimePreprocessor}.class. - *

- * - * @author Jonathan Hale (University of Konstanz) - */ -public interface KnimePreprocessor extends PreprocessorPlugin { - // Marker interface -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/AbstractDefaultSettingsService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/AbstractDefaultSettingsService.java deleted file mode 100644 index 9c5f370..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/AbstractDefaultSettingsService.java +++ /dev/null @@ -1,186 +0,0 @@ -package org.knime.scijava.commands.settings; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.knime.core.node.InvalidSettingsException; -import org.knime.core.node.NodeSettingsRO; -import org.knime.core.node.NodeSettingsWO; -import org.knime.core.node.defaultnodesettings.SettingsModel; -import org.knime.core.node.defaultnodesettings.SettingsModelString; -import org.knime.scijava.commands.KNIMESciJavaConstants; -import org.scijava.module.Module; -import org.scijava.module.ModuleItem; -import org.scijava.plugin.Parameter; -import org.scijava.service.AbstractService; - -/** - * Default implementation of NodeSettingsService. - * - * @author Jonathan Hale (University of Konstanz) - */ -@SuppressWarnings("rawtypes") -public abstract class AbstractDefaultSettingsService extends AbstractService - implements NodeSettingsService { - - private WeakReference> m_settingsModels = new WeakReference<>( - null); - - @Parameter - SettingsModelTypeService m_typeService; - - /* - * @return Map referenced by m_settingsModels or empty Map. Never - * null - */ - protected Map getSafeSettingsModelsMap() { - if (m_settingsModels.get() == null) { - m_settingsModels = new WeakReference<>(new HashMap<>()); - } - - return m_settingsModels.get(); - } - - @SuppressWarnings("unchecked") - @Override - public void setValue(final ModuleItem moduleItem, final Object value) { - final SettingsModel sm = getSafeSettingsModelsMap() - .get(moduleItem.getName()); - if (sm == null) { - return; - } - - final SettingsModelType t = m_typeService.getSettingsModelTypeFor(sm); - - t.setValue(sm, value); - } - - @Override - public Object getValue(final ModuleItem moduleItem) { - final SettingsModel sm = getSafeSettingsModelsMap() - .get(moduleItem.getName()); - if (sm == null) { - return null; - } - - final SettingsModelType t = m_typeService.getSettingsModelTypeFor(sm); - if (t != null) { - return t.getValue(sm); - } - - return null; - } - - private SettingsModel createSettingsModel(final ModuleItem moduleItem, - Module module, final boolean forceColSelec) { - SettingsModel sm; - - // check for if columnselection is forced - if (forceColSelec) { - sm = createColSelectModel(moduleItem); - } else { - final SettingsModelType t = m_typeService - .getSettingsModelTypeFor(moduleItem.getType()); - if (t != null) { - // get default value - Object value = moduleItem.getValue(module); - if (value != null) { - sm = t.create(moduleItem.getName(), value); - // set to default value - t.setValue(sm, moduleItem.getValue(module)); - } else { - sm = t.create(moduleItem.getName(), - moduleItem.getMinimumValue()); - } - } else { - // can't create a SettingsModel for this type, we will try to - // create a column selection Widget. - sm = createColSelectModel(moduleItem); - } - } - return sm; - } - - private SettingsModel createColSelectModel(final ModuleItem moduleItem) { - return new SettingsModelString(moduleItem.getName(), ""); - } - - @Override - public SettingsModel createAndAddSettingsModel( - final ModuleItem moduleItem, Module module, - final boolean forceColumnSelection) { - SettingsModel sm = getSafeSettingsModelsMap().get(moduleItem.getName()); - if (sm != null) { - return sm; // already exists, do not overwrite. - } - - sm = createSettingsModel(moduleItem, module, forceColumnSelection); - getSafeSettingsModelsMap().put(moduleItem.getName(), sm); - return sm; - } - - @Override - public List createAndAddSettingsModels( - final Iterable> moduleItems, Module module) { - final ArrayList settingsModels = new ArrayList<>(); - moduleItems.forEach(item -> { - final boolean force = "true".equals( - item.get(KNIMESciJavaConstants.COLUMN_SELECT_KEY)); - settingsModels.add(createAndAddSettingsModel(item, module, force)); - }); - - return settingsModels; - } - - @Override - public boolean validateSettings(final NodeSettingsRO settings) - throws InvalidSettingsException { - for (final SettingsModel sm : getSafeSettingsModelsMap().values()) { - sm.validateSettings(settings); - } - - return true; - } - - @Override - public boolean loadSettingsFrom(final NodeSettingsRO settings, - final boolean tolerant) throws InvalidSettingsException { - final Collection values = getSafeSettingsModelsMap() - .values(); - for (final SettingsModel sm : values) { - try { - sm.loadSettingsFrom(settings); - } catch (final InvalidSettingsException e) { - if (!tolerant) { - throw e; - } - } - } - - return true; - } - - @Override - public boolean saveSettingsTo(final NodeSettingsWO settings) { - final Collection values = getSafeSettingsModelsMap() - .values(); - for (final SettingsModel sm : values) { - sm.saveSettingsTo(settings); - } - return true; - } - - @Override - public void clear() { - getSafeSettingsModelsMap().clear(); - } - - @Override - public void removeSettingsModel(final ModuleItem moduleItem) { - getSafeSettingsModelsMap().remove(moduleItem.getName()); - } -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeDialogSettingsService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeDialogSettingsService.java deleted file mode 100644 index 5d4ce28..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeDialogSettingsService.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.knime.scijava.commands.settings; - -import org.scijava.plugin.Plugin; - -/** - * Marker class - * - * @author gabriel - * - */ - -@Plugin(type = NodeDialogSettingsService.class) -public class DefaultNodeDialogSettingsService extends - AbstractDefaultSettingsService implements NodeDialogSettingsService { - // NB Marker class -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeModelSettingsService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeModelSettingsService.java deleted file mode 100644 index ed255c9..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeModelSettingsService.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.knime.scijava.commands.settings; - -import org.scijava.plugin.Plugin; - -/** - * Marker class - * - * @author gabriel - * - */ - -@Plugin(type = NodeModelSettingsService.class) -public class DefaultNodeModelSettingsService extends - AbstractDefaultSettingsService implements NodeModelSettingsService { - // NB Marker class -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeSettingsHarvester.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeSettingsHarvester.java deleted file mode 100644 index 47c75d0..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeSettingsHarvester.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.knime.scijava.commands.settings; - -import org.scijava.Priority; -import org.scijava.log.LogService; -import org.scijava.module.Module; -import org.scijava.module.ModuleItem; -import org.scijava.module.process.AbstractPreprocessorPlugin; -import org.scijava.module.process.PreprocessorPlugin; -import org.scijava.plugin.Parameter; -import org.scijava.plugin.Plugin; - -/** - * Default implementation of NodeSettingsHarvester. - * - * @author Jonathan Hale (University of Konstanz) - */ -@Plugin(type = PreprocessorPlugin.class, priority = Priority.NORMAL_PRIORITY) -public class DefaultNodeSettingsHarvester extends AbstractPreprocessorPlugin - implements NodeSettingsHarvester { - - @Parameter - NodeSettingsService m_settingsService; - - @Parameter - LogService log; - - @Override - public void process(final Module module) { - for (final ModuleItem input : module.getInfo().inputs()) { - // shortcut to inputName - final String inputName = input.getName(); - - if (!module.isResolved(inputName)) { - // we will not overwrite resolved input values - - // get settings for this input - final Object value = m_settingsService.getValue(input); - - if (value != null) { - // we have settings for this input - module.setInput(inputName, value); - module.setResolved(inputName, true); - } - } - } - } - -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeSettingsService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeSettingsService.java new file mode 100644 index 0000000..62fe129 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultNodeSettingsService.java @@ -0,0 +1,66 @@ +package org.knime.scijava.commands.settings; + +import org.knime.core.node.defaultnodesettings.SettingsModel; +import org.knime.core.node.defaultnodesettings.SettingsModelString; +import org.knime.scijava.commands.converter.KNIMEConverterService; +import org.scijava.module.ModuleItem; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; +import org.scijava.service.AbstractService; + +/** + * Default implementation of {@link NodeSettingsService} + * + * @author Christian Dietz, University of Konstanz + */ +@Plugin(type = NodeSettingsService.class) +public class DefaultNodeSettingsService extends AbstractService + implements NodeSettingsService { + + @Parameter + private KNIMEConverterService cs; + + @Parameter + private SettingsModelTypeService typeService; + + @Override + public Object getValue(final SettingsModel model) { + return typeService.getValueFrom(model); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public SettingsModel createSettingsModel(final ModuleItem item) { + SettingsModel sm = null; + + if (item.isInput()) { + final SettingsModelType t = typeService + .getSettingsModelTypeFor(item); + if (t != null) { + // get default value + final Object value = item.getDefaultValue(); + if (value != null) { + sm = t.create(item.getName(), value); + // set to default value + t.setValue(sm, value); + } else { + sm = t.create(item.getName(), item.getMinimumValue()); + } + } + } else { + sm = new SettingsModelString(item.getName(), + cs.getMatchingFactories(item.getType()).iterator().next() + .getDestinationType().getCellClass().getName()); + } + + return sm; + } + + @SuppressWarnings("unchecked") + @Override + public void setValue(final SettingsModel settingsModel, + final Object value) { + typeService.getSettingsModelTypeFor(settingsModel) + .setValue(settingsModel, value); + } +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultSettingsModelTypeService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultSettingsModelTypeService.java index a589caa..9e06dce 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultSettingsModelTypeService.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/DefaultSettingsModelTypeService.java @@ -3,9 +3,14 @@ import java.util.HashMap; import java.util.Map; +import org.knime.core.data.convert.util.ClassUtil; import org.knime.core.node.defaultnodesettings.SettingsModel; -import org.knime.scijava.commands.util.PrimitiveTypeUtils; +import org.knime.scijava.commands.StyleHook; +import org.knime.scijava.commands.converter.KNIMEConverterService; +import org.knime.scijava.commands.settings.types.SettingsModelColumnSelectionType; +import org.scijava.module.ModuleItem; import org.scijava.plugin.AbstractSingletonService; +import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; /** @@ -20,60 +25,80 @@ @SuppressWarnings("rawtypes") @Plugin(type = SettingsModelTypeService.class) public class DefaultSettingsModelTypeService - extends AbstractSingletonService - implements SettingsModelTypeService { - - private final Map, SettingsModelTypePlugin> m_pluginsByModel = new HashMap<>(); - private final Map, SettingsModelTypePlugin> m_pluginsByValue = new HashMap<>(); - - @Override - public Class getPluginType() { - return SettingsModelTypePlugin.class; - } - - @Override - public SettingsModelType getSettingsModelTypeFor( - final SettingsModel settingsModel) { - - final SettingsModelTypePlugin plugin = m_pluginsByModel - .get(settingsModel.getClass()); - if (plugin != null) { - return plugin; - } - - for (final SettingsModelTypePlugin p : getInstances()) { - if (p.getSettingsModelClass().isInstance(settingsModel)) { - m_pluginsByModel.put(settingsModel.getClass(), p); - return p; - } - } - // nothing found - return null; - } - - @Override - public SettingsModelType getSettingsModelTypeFor(final Class value) { - - // check cache - final SettingsModelTypePlugin plugin = m_pluginsByValue.get(value); - if (plugin != null) { - return plugin; - } - - // check primitive conversion cache - final Class checkValue = PrimitiveTypeUtils - .convertIfPrimitive(value); - - // search - for (final SettingsModelTypePlugin p : getInstances()) { - if (p.getValueClass().isAssignableFrom(checkValue)) { - m_pluginsByValue.put(value, p); - return p; - } - } - - // nothing found - return null; - } + extends AbstractSingletonService + implements SettingsModelTypeService { + + @Parameter + private KNIMEConverterService cs; + + private final Map, SettingsModelType> m_pluginsByModel = new HashMap<>(); + private final Map, SettingsModelType> m_pluginsByValue = new HashMap<>(); + + @Override + public SettingsModelType getSettingsModelTypeFor( + final SettingsModel settingsModel) { + + final SettingsModelType plugin = m_pluginsByModel + .get(settingsModel.getClass()); + if (plugin != null) { + return plugin; + } + + for (final SettingsModelType p : getInstances()) { + if (p.getSettingsModelClass().isInstance(settingsModel)) { + m_pluginsByModel.put(settingsModel.getClass(), p); + return p; + } + } + // nothing found + return null; + } + + @Override + public SettingsModelType getSettingsModelTypeFor(final ModuleItem item) { + if (StyleHook.COLUMNSELECTION.equals(item.getWidgetStyle())) { + return new SettingsModelColumnSelectionType(); + } else { + // check cache + final SettingsModelType plugin = m_pluginsByValue + .get(item.getType()); + if (plugin != null) { + return plugin; + } + + // check primitive conversion cache + + // search + for (final SettingsModelType p : getInstances()) { + if (p instanceof SettingsModelColumnSelectionType) { + continue; + } + if (p.getValueClass().isAssignableFrom( + ClassUtil.ensureObjectType(item.getType()))) { + m_pluginsByValue.put(item.getType(), p); + return p; + } + } + + // check for column selection + if (cs.getMatchingInputValueClass(item.getType()).isPresent()) { + return new SettingsModelColumnSelectionType(); + } + } + + // nothing found + return null; + } + + @SuppressWarnings("unchecked") + @Override + public Object getValueFrom(final SettingsModel model) { + return getSettingsModelTypeFor(model).getValue(model); + } + + @Override + public Class getPluginType() { + return SettingsModelType.class; + } } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeDialogSettingsService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeDialogSettingsService.java deleted file mode 100644 index 6e16632..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeDialogSettingsService.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.knime.scijava.commands.settings; - -import org.scijava.plugin.Plugin; - -/** - * Marker interface for the SettingsService that stores the settings of the node - * dialog. - * - *

- * NodeDialogSettingsService plugins discoverable at runtime must implement this - * interface and be annotated with @{@link Plugin} with attribute - * {@link Plugin#type()} = {@link NodeDialogSettingsService}.class. - *

- * - * - * @author Gabriel Einsdorf (University of Konstanz) - * - */ -public interface NodeDialogSettingsService extends NodeSettingsService { - // NB Marker Interface -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeModelSettingsService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeModelSettingsService.java deleted file mode 100644 index 0e86e5b..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeModelSettingsService.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.knime.scijava.commands.settings; - -import org.scijava.plugin.Plugin; - -/** - * Marker interface for the SettingsService that stores the settings of the node - * dialog. - * - *

- * NodeDialogSettingsService plugins discoverable at runtime must implement this - * interface and be annotated with @{@link Plugin} with attribute - * {@link Plugin#type()} = {@link NodeModelSettingsService}.class. - *

- * - * - * @author Gabriel Einsdorf (University of Konstanz) - * - */ -public interface NodeModelSettingsService extends NodeSettingsService { - // NB Marker Interface -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeSettingsHarvester.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeSettingsHarvester.java deleted file mode 100644 index 60d1539..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeSettingsHarvester.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.knime.scijava.commands.settings; - -import org.scijava.module.process.PreprocessorPlugin; -import org.scijava.plugin.Plugin; - -/** - * A preprocessor that handles unresolved parameters of various types using a - * {@link NodeSettingsService}. - * - *

- * NodeSettingsHarvester plugins discoverable at runtime must implement this - * interface and be annotated with @{@link Plugin} with attribute - * {@link Plugin#type()} = {@link NodeSettingsHarvester}.class. - *

- * - * @author Jonathan Hale (University of Konstanz) - * - */ -public interface NodeSettingsHarvester extends PreprocessorPlugin { - // NB: marker interface -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeSettingsService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeSettingsService.java index 64eb88a..808021b 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeSettingsService.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/NodeSettingsService.java @@ -1,125 +1,72 @@ package org.knime.scijava.commands.settings; -import java.lang.ref.WeakReference; -import java.util.List; +import java.util.HashMap; import java.util.Map; -import org.knime.core.node.InvalidSettingsException; -import org.knime.core.node.NodeDialog; -import org.knime.core.node.NodeModel; -import org.knime.core.node.NodeSettingsRO; -import org.knime.core.node.NodeSettingsWO; import org.knime.core.node.defaultnodesettings.SettingsModel; -import org.scijava.module.Module; +import org.knime.scijava.commands.MultiOutputListener; +import org.scijava.module.ModuleInfo; import org.scijava.module.ModuleItem; -import org.scijava.plugin.Plugin; import org.scijava.service.Service; /** - * Interface for Services that provide functionality to create and modify - * {@link SettingsModel}s. It holds a {@link Map} of {@link SettingsModel}s with - * a {@link WeakReference} to manage the SettingsModels for a {@link NodeModel} - * or {@link NodeDialog}, but not prevent the {@link SettingsModel}s to be - * garbage collected when the NodeModel or NodeDialog are destroyed. - * - *

- * NodeSettingsService plugins discoverable at runtime must implement this - * interface and be annotated with @{@link Plugin} with attribute - * {@link Plugin#type()} = {@link NodeSettingsService}.class. - *

- * - * @author Jonathan Hale (University of Konstanz) + * Interface for services which handle SettingsModels. * + * @author Christian Dietz, University of Konstanz */ public interface NodeSettingsService extends Service { - /** - * Set the value of the SettingsModel for a ModuleItem. Prints a warning if - * no SettingsModel exists for the passed moduleItem. - * - * @param moduleItem - * name of the SettingsModel - * @param value - * value to set the SettingsModels value to. - */ - void setValue(ModuleItem moduleItem, Object value); - - /** - * Get the value of the SettingsModel of the given ModuleItem. - * - * @param moduleItem - * @return the value of the found SettingsModel. - */ - Object getValue(ModuleItem moduleItem); - - /** - * Create a new {@link SettingsModel} for a {@link ModuleItem} and add it to - * the {@link Map} of {@link SettingsModel}s set via - * {@link #setSettingsModels(Map)}. - * - * @param moduleItem - * ModuleItem to create a SettingsModel for. - * @param module - * the module, the moduleItem is from. - * @return the created SettignsModel or null if no SettingsModel could be - * created for moduleItem. - * @see #createSettingsModel(ModuleItem) - * @see #createSettingsModels(Iterable) - */ - SettingsModel createAndAddSettingsModel(ModuleItem moduleItem, - Module module, boolean forceColumnSelection); + /** + * Get all settings models for a given module. + * + * @param module + * the module to get {@link SettingsModels} for. + * @return Map of settings models with module item names as keys. + */ + default Map getSettingsModels( + final ModuleInfo module) { + final Map models = new HashMap<>(); - /** - * Create new {@link SettingsModel}s for ModuleItems and add them to the - * {@link Map} set via {@link #setSettingsModels(Map)}. - * - * @param moduleItems - * @return the created SettingsModels - */ - List createAndAddSettingsModels( - Iterable> moduleItems, Module module); + for (final ModuleItem item : module.inputs()) { + // FIXME make extensible? + if (MultiOutputListener.class.isAssignableFrom(item.getType())) { + continue; + } + models.put(item.getName(), createSettingsModel(item)); + } - /** - * Validate all settingsModels in this service. - * - * @param settings - * @return true on success - * @throws InvalidSettingsException - */ - boolean validateSettings(NodeSettingsRO settings) - throws InvalidSettingsException; + for (final ModuleItem item : module.outputs()) { + models.put(item.getName(), createSettingsModel(item)); + } - /** - * Load settings in this service from settings. - * - * @param settings - * Settings to load from - * @param tolerant - * Whether to tolerate missing values - * @return true on success - * @throws InvalidSettingsException - */ - boolean loadSettingsFrom(NodeSettingsRO settings, boolean tolerant) - throws InvalidSettingsException; + return models; + } - /** - * Save settings in this service to settings. - * - * @param settings - * @return true on success - */ - boolean saveSettingsTo(NodeSettingsWO settings); + /** + * Create settings model for a given module item. + * + * @param moduleItem + * the module item to create a settings model for. + * @return The created {@link SettingsModel} + */ + SettingsModel createSettingsModel(final ModuleItem moduleItem); - /** - * Removes all settings from the Service. - */ - void clear(); + /** + * Dynamically get the value of a {@link SettingsModel}. + * + * @param model + * the model to get the value of. + * @return the value + */ + Object getValue(final SettingsModel model); - /** - * Removes the settingsModel associated with the given module item (input). - * - * @param item - * the item which settings model will be removed. - */ - void removeSettingsModel(ModuleItem item); + /** + * Dynamically set the value of a {@link SettingsModel}. + * + * @param settingsModel + * model to set the value of. + * @param value + * Value to set to + */ + void setValue(final SettingsModel settingsModel, final Object value); } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/SettingsModelType.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/SettingsModelType.java index bba56e4..6932678 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/SettingsModelType.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/SettingsModelType.java @@ -1,6 +1,7 @@ package org.knime.scijava.commands.settings; import org.knime.core.node.defaultnodesettings.SettingsModel; +import org.scijava.plugin.SingletonPlugin; /** * Interface for SettingsModelTypes which set and get values from @@ -19,52 +20,53 @@ * TODO: This sadly doesn't do the job. Sometimes it is not possible * to set set value just from Object. */ -public interface SettingsModelType { +public interface SettingsModelType + extends SingletonPlugin { - /** - * Create a new SettingsModel instance with type described by this - * SettingsModelType. - * - * @param name - * Name of the SettingsModel. - * @param defaultValue - * DefaultValue for this SettingsModel - * @return - */ - public T create(String name, V defaultValue); + /** + * Create a new SettingsModel instance with type described by this + * SettingsModelType. + * + * @param name + * Name of the SettingsModel. + * @param defaultValue + * DefaultValue for this SettingsModel + * @return + */ + public T create(String name, V defaultValue); - /** - * Set the value of a SettingsModel. - * - * @param settingsModel - * SettingsModel to set the value of. - * @param value - * value to set to. - */ - public void setValue(T settingsModel, V value); + /** + * Set the value of a SettingsModel. + * + * @param settingsModel + * SettingsModel to set the value of. + * @param value + * value to set to. + */ + public void setValue(T settingsModel, V value); - /** - * Get the value of a SettingsModel. - * - * @param settingsModel - * SettingsModel to get the value of. - * @return the value of the SettingsModel. - */ - public V getValue(T settingsModel); + /** + * Get the value of a SettingsModel. + * + * @param settingsModel + * SettingsModel to get the value of. + * @return the value of the SettingsModel. + */ + public V getValue(T settingsModel); - /** - * Get the SettingsModel class this SettingsModelType can set and get values - * of. - * - * @return a SettingsModel subclass. - */ - public Class getSettingsModelClass(); + /** + * Get the SettingsModel class this SettingsModelType can set and get values + * of. + * + * @return a SettingsModel subclass. + */ + public Class getSettingsModelClass(); - /** - * Get the class of the value which can be set to/get from the - * SettingsModel. - * - * @return class of the value. - */ - public Class getValueClass(); + /** + * Get the class of the value which can be set to/get from the + * SettingsModel. + * + * @return class of the value. + */ + public Class getValueClass(); } \ No newline at end of file diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/SettingsModelTypePlugin.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/SettingsModelTypePlugin.java deleted file mode 100644 index 06725b8..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/SettingsModelTypePlugin.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.knime.scijava.commands.settings; - -import org.knime.core.node.defaultnodesettings.SettingsModel; -import org.scijava.plugin.Plugin; -import org.scijava.plugin.SingletonPlugin; - -/** - * A plugin which extends {@link SettingsModel} adapting capabilities. - * - *

- * SettingsModelTypePlugin plugins discoverable at runtime must implement this - * interface and be annotated with @{@link Plugin} with attribute - * {@link Plugin#type()} = {@link SettingsModelTypePlugin}.class. - *

- * - * @author Jonathan Hale (University of Konstanz) - * - * @param - * @param - */ -public interface SettingsModelTypePlugin - extends SettingsModelType, SingletonPlugin { - // Marker interface -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/SettingsModelTypeService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/SettingsModelTypeService.java index 8979d25..904dd93 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/SettingsModelTypeService.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/SettingsModelTypeService.java @@ -1,6 +1,7 @@ package org.knime.scijava.commands.settings; import org.knime.core.node.defaultnodesettings.SettingsModel; +import org.scijava.module.ModuleItem; import org.scijava.plugin.Plugin; import org.scijava.plugin.SingletonService; @@ -17,28 +18,36 @@ */ @SuppressWarnings("rawtypes") public interface SettingsModelTypeService - extends SingletonService { + extends SingletonService { - /** - * Get a SettingModelType which can set and get values from the specified - * SettingsModel. - * - * @param settingsModel - * SettingsModel to find a SettingsModelType for. - * @return a SettingsModelType which can set/get values from settingsModel - * or null if none could be found or settingsModel was - * null. - */ - SettingsModelType getSettingsModelTypeFor(SettingsModel settingsModel); + /** + * Get a SettingModelType which can set and get values from the specified + * SettingsModel. + * + * @param settingsModel + * SettingsModel to find a SettingsModelType for. + * @return a SettingsModelType which can set/get values from settingsModel + * or null if none could be found or settingsModel was + * null. + */ + SettingsModelType getSettingsModelTypeFor( + final SettingsModel settingsModel); - /** - * Get a SettingsModelType which can assign the given value to a - * SettingsModel. - * - * @param value - * the value which to store in a SettingsModel. - * @return SettingsModelType which stores values of given value type. - */ - SettingsModelType getSettingsModelTypeFor(Class value); + /** + * Get the {@link SettingsModelType} matching the given {@link ModuleItem}. + * + * @param item + * The item to get the settings model type for + * @return the matching settings model type + */ + SettingsModelType getSettingsModelTypeFor(final ModuleItem item); + /** + * Dynamically get the value of a {@link SettingsModel}. + * + * @param model + * The settings model + * @return value contained in the {@link SettingsModel} + */ + Object getValueFrom(final SettingsModel model); } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/models/SettingsModelColumnSelection.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/models/SettingsModelColumnSelection.java new file mode 100644 index 0000000..4cbc162 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/models/SettingsModelColumnSelection.java @@ -0,0 +1,46 @@ +package org.knime.scijava.commands.settings.models; + +import org.knime.core.data.DataTableSpec; +import org.knime.core.node.defaultnodesettings.SettingsModelString; + +/** + * SettingsModel for columns. + * + * @author Christian Dietz, University of Konstanz + */ +public class SettingsModelColumnSelection extends SettingsModelString { + + private DataTableSpec spec; + + /** + * Constructor. + * + * @param configName + * Name of the setting + * @param defaultValue + * Default value + */ + public SettingsModelColumnSelection(final String configName, + final String defaultValue) { + super(configName, defaultValue); + } + + /** + * Set data table spec. + * + * @param spec + * the spec to set + */ + public void setSpec(final DataTableSpec spec) { + this.spec = spec; + } + + /** + * Get the contained DataTableSpec. + * + * @return the spec + */ + public DataTableSpec getSpec() { + return spec; + }; +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelAggregationMethodType.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelAggregationMethodType.java index c2218c5..723e50d 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelAggregationMethodType.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelAggregationMethodType.java @@ -2,7 +2,7 @@ import org.knime.base.data.aggregation.AggregationMethod; import org.knime.base.data.aggregation.dialogutil.SettingsModelAggregationMethod; -import org.knime.scijava.commands.settings.SettingsModelTypePlugin; +import org.knime.scijava.commands.settings.SettingsModelType; import org.scijava.plugin.Plugin; /** @@ -10,36 +10,36 @@ * * @author Jonathan Hale (University of Konstanz) */ -@Plugin(type = SettingsModelTypePlugin.class) +@Plugin(type = SettingsModelType.class) public class SettingsModelAggregationMethodType implements - SettingsModelTypePlugin { - - @Override - public SettingsModelAggregationMethod create(final String name, - final AggregationMethod defaultValue) { - return new SettingsModelAggregationMethod(name, defaultValue); - } - - @Override - public void setValue(final SettingsModelAggregationMethod settingsModel, - final AggregationMethod value) { - settingsModel.setAggregationMethod(value); - } - - @Override - public AggregationMethod getValue( - final SettingsModelAggregationMethod settingsModel) { - return settingsModel.getAggregationMethod(); - } - - @Override - public Class getSettingsModelClass() { - return SettingsModelAggregationMethod.class; - } - - @Override - public Class getValueClass() { - return AggregationMethod.class; - } + SettingsModelType { + + @Override + public SettingsModelAggregationMethod create(final String name, + final AggregationMethod defaultValue) { + return new SettingsModelAggregationMethod(name, defaultValue); + } + + @Override + public void setValue(final SettingsModelAggregationMethod settingsModel, + final AggregationMethod value) { + settingsModel.setAggregationMethod(value); + } + + @Override + public AggregationMethod getValue( + final SettingsModelAggregationMethod settingsModel) { + return settingsModel.getAggregationMethod(); + } + + @Override + public Class getSettingsModelClass() { + return SettingsModelAggregationMethod.class; + } + + @Override + public Class getValueClass() { + return AggregationMethod.class; + } } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelBooleanType.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelBooleanType.java index e9fbcae..744d5d7 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelBooleanType.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelBooleanType.java @@ -1,7 +1,7 @@ package org.knime.scijava.commands.settings.types; import org.knime.core.node.defaultnodesettings.SettingsModelBoolean; -import org.knime.scijava.commands.settings.SettingsModelTypePlugin; +import org.knime.scijava.commands.settings.SettingsModelType; import org.scijava.plugin.Plugin; /** @@ -9,38 +9,38 @@ * * @author Jonathan Hale (University of Konstanz) */ -@Plugin(type = SettingsModelTypePlugin.class) +@Plugin(type = SettingsModelType.class) public class SettingsModelBooleanType - implements SettingsModelTypePlugin { - - @Override - public SettingsModelBoolean create(final String name, - final Boolean defaultValue) { - if (defaultValue == null) { - return new SettingsModelBoolean(name, false); - } - return new SettingsModelBoolean(name, defaultValue); - } - - @Override - public void setValue(final SettingsModelBoolean settingsModel, - final Boolean value) { - settingsModel.setBooleanValue(value); - } - - @Override - public Boolean getValue(final SettingsModelBoolean settingsModel) { - return settingsModel.getBooleanValue(); - } - - @Override - public Class getSettingsModelClass() { - return SettingsModelBoolean.class; - } - - @Override - public Class getValueClass() { - return Boolean.class; - } + implements SettingsModelType { + + @Override + public SettingsModelBoolean create(final String name, + final Boolean defaultValue) { + if (defaultValue == null) { + return new SettingsModelBoolean(name, false); + } + return new SettingsModelBoolean(name, defaultValue); + } + + @Override + public void setValue(final SettingsModelBoolean settingsModel, + final Boolean value) { + settingsModel.setBooleanValue(value); + } + + @Override + public Boolean getValue(final SettingsModelBoolean settingsModel) { + return settingsModel.getBooleanValue(); + } + + @Override + public Class getSettingsModelClass() { + return SettingsModelBoolean.class; + } + + @Override + public Class getValueClass() { + return Boolean.class; + } } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelColorType.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelColorType.java index d693100..7498842 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelColorType.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelColorType.java @@ -3,7 +3,7 @@ import java.awt.Color; import org.knime.core.node.defaultnodesettings.SettingsModelColor; -import org.knime.scijava.commands.settings.SettingsModelTypePlugin; +import org.knime.scijava.commands.settings.SettingsModelType; import org.scijava.plugin.Plugin; /** @@ -11,38 +11,38 @@ * * @author Jonathan Hale (University of Konstanz) */ -@Plugin(type = SettingsModelTypePlugin.class) +@Plugin(type = SettingsModelType.class) public class SettingsModelColorType - implements SettingsModelTypePlugin { - - @Override - public SettingsModelColor create(final String name, - final Color defaultValue) { - if (defaultValue == null) { - return new SettingsModelColor(name, Color.RED); - } - return new SettingsModelColor(name, defaultValue); - } - - @Override - public void setValue(final SettingsModelColor settingsModel, - final Color value) { - settingsModel.setColorValue(value); - } - - @Override - public Color getValue(final SettingsModelColor settingsModel) { - return settingsModel.getColorValue(); - } - - @Override - public Class getSettingsModelClass() { - return SettingsModelColor.class; - } - - @Override - public Class getValueClass() { - return Color.class; - } + implements SettingsModelType { + + @Override + public SettingsModelColor create(final String name, + final Color defaultValue) { + if (defaultValue == null) { + return new SettingsModelColor(name, Color.RED); + } + return new SettingsModelColor(name, defaultValue); + } + + @Override + public void setValue(final SettingsModelColor settingsModel, + final Color value) { + settingsModel.setColorValue(value); + } + + @Override + public Color getValue(final SettingsModelColor settingsModel) { + return settingsModel.getColorValue(); + } + + @Override + public Class getSettingsModelClass() { + return SettingsModelColor.class; + } + + @Override + public Class getValueClass() { + return Color.class; + } } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelColumnSelectionType.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelColumnSelectionType.java new file mode 100644 index 0000000..54be6ef --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelColumnSelectionType.java @@ -0,0 +1,43 @@ +package org.knime.scijava.commands.settings.types; + +import org.knime.scijava.commands.settings.SettingsModelType; +import org.knime.scijava.commands.settings.models.SettingsModelColumnSelection; +import org.scijava.plugin.Plugin; + +/** + * SettingsModelType implementation for SettingsModelColumnSelection. + * + * @author Christian Dietz, University of Konstanz + */ +@Plugin(type = SettingsModelType.class) +public class SettingsModelColumnSelectionType + implements SettingsModelType { + + @Override + public SettingsModelColumnSelection create(final String name, + final String defaultValue) { + return new SettingsModelColumnSelection(name, defaultValue); + } + + @Override + public void setValue(final SettingsModelColumnSelection settingsModel, + final String value) { + settingsModel.setStringValue(value); + } + + @Override + public String getValue(final SettingsModelColumnSelection settingsModel) { + return settingsModel.getStringValue(); + } + + @Override + public Class getSettingsModelClass() { + return SettingsModelColumnSelection.class; + } + + @Override + public Class getValueClass() { + return String.class; + } + +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelDoubleType.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelDoubleType.java index f538c09..1aeacb9 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelDoubleType.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelDoubleType.java @@ -1,7 +1,7 @@ package org.knime.scijava.commands.settings.types; import org.knime.core.node.defaultnodesettings.SettingsModelDouble; -import org.knime.scijava.commands.settings.SettingsModelTypePlugin; +import org.knime.scijava.commands.settings.SettingsModelType; import org.scijava.plugin.Plugin; /** @@ -9,38 +9,38 @@ * * @author Jonathan Hale (University of Konstanz) */ -@Plugin(type = SettingsModelTypePlugin.class) +@Plugin(type = SettingsModelType.class) public class SettingsModelDoubleType - implements SettingsModelTypePlugin { - - @Override - public SettingsModelDouble create(final String name, - final Double defaultValue) { - if (defaultValue == null) { - return new SettingsModelDouble(name, 0.0d); - } - return new SettingsModelDouble(name, defaultValue); - } - - @Override - public void setValue(final SettingsModelDouble settingsModel, - final Double value) { - settingsModel.setDoubleValue(value); - } - - @Override - public Double getValue(final SettingsModelDouble settingsModel) { - return settingsModel.getDoubleValue(); - } - - @Override - public Class getSettingsModelClass() { - return SettingsModelDouble.class; - } - - @Override - public Class getValueClass() { - return Double.class; - } + implements SettingsModelType { + + @Override + public SettingsModelDouble create(final String name, + final Double defaultValue) { + if (defaultValue == null) { + return new SettingsModelDouble(name, 0.0d); + } + return new SettingsModelDouble(name, defaultValue); + } + + @Override + public void setValue(final SettingsModelDouble settingsModel, + final Double value) { + settingsModel.setDoubleValue(value); + } + + @Override + public Double getValue(final SettingsModelDouble settingsModel) { + return settingsModel.getDoubleValue(); + } + + @Override + public Class getSettingsModelClass() { + return SettingsModelDouble.class; + } + + @Override + public Class getValueClass() { + return Double.class; + } } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelIntegerType.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelIntegerType.java index 9ae6e11..48dd4bb 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelIntegerType.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelIntegerType.java @@ -1,7 +1,7 @@ package org.knime.scijava.commands.settings.types; import org.knime.core.node.defaultnodesettings.SettingsModelInteger; -import org.knime.scijava.commands.settings.SettingsModelTypePlugin; +import org.knime.scijava.commands.settings.SettingsModelType; import org.scijava.plugin.Plugin; /** @@ -9,38 +9,38 @@ * * @author Jonathan Hale (University of Konstanz) */ -@Plugin(type = SettingsModelTypePlugin.class) +@Plugin(type = SettingsModelType.class) public class SettingsModelIntegerType - implements SettingsModelTypePlugin { - - @Override - public SettingsModelInteger create(final String name, - final Integer defaultValue) { - if (defaultValue == null) { - return new SettingsModelInteger(name, 0); - } - return new SettingsModelInteger(name, defaultValue); - } - - @Override - public void setValue(final SettingsModelInteger settingsModel, - final Integer value) throws ClassCastException { - settingsModel.setIntValue(value); - } - - @Override - public Integer getValue(final SettingsModelInteger settingsModel) { - return settingsModel.getIntValue(); - } - - @Override - public Class getSettingsModelClass() { - return SettingsModelInteger.class; - } - - @Override - public Class getValueClass() { - return Integer.class; - } + implements SettingsModelType { + + @Override + public SettingsModelInteger create(final String name, + final Integer defaultValue) { + if (defaultValue == null) { + return new SettingsModelInteger(name, 0); + } + return new SettingsModelInteger(name, defaultValue); + } + + @Override + public void setValue(final SettingsModelInteger settingsModel, + final Integer value) throws ClassCastException { + settingsModel.setIntValue(value); + } + + @Override + public Integer getValue(final SettingsModelInteger settingsModel) { + return settingsModel.getIntValue(); + } + + @Override + public Class getSettingsModelClass() { + return SettingsModelInteger.class; + } + + @Override + public Class getValueClass() { + return Integer.class; + } } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelLongType.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelLongType.java index ff171d7..c4f8f81 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelLongType.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelLongType.java @@ -1,7 +1,7 @@ package org.knime.scijava.commands.settings.types; import org.knime.core.node.defaultnodesettings.SettingsModelLong; -import org.knime.scijava.commands.settings.SettingsModelTypePlugin; +import org.knime.scijava.commands.settings.SettingsModelType; import org.scijava.plugin.Plugin; /** @@ -9,38 +9,38 @@ * * @author Jonathan Hale (University of Konstanz) */ -@Plugin(type = SettingsModelTypePlugin.class) +@Plugin(type = SettingsModelType.class) public class SettingsModelLongType - implements SettingsModelTypePlugin { - - @Override - public SettingsModelLong create(final String name, - final Long defaultValue) { - if (defaultValue == null) { - return new SettingsModelLong(name, 0); - } - return new SettingsModelLong(name, defaultValue); - } - - @Override - public void setValue(final SettingsModelLong settingsModel, - final Long value) throws ClassCastException { - settingsModel.setLongValue(value); - } - - @Override - public Long getValue(final SettingsModelLong settingsModel) { - return settingsModel.getLongValue(); - } - - @Override - public Class getSettingsModelClass() { - return SettingsModelLong.class; - } - - @Override - public Class getValueClass() { - return Long.class; - } + implements SettingsModelType { + + @Override + public SettingsModelLong create(final String name, + final Long defaultValue) { + if (defaultValue == null) { + return new SettingsModelLong(name, 0); + } + return new SettingsModelLong(name, defaultValue); + } + + @Override + public void setValue(final SettingsModelLong settingsModel, + final Long value) throws ClassCastException { + settingsModel.setLongValue(value); + } + + @Override + public Long getValue(final SettingsModelLong settingsModel) { + return settingsModel.getLongValue(); + } + + @Override + public Class getSettingsModelClass() { + return SettingsModelLong.class; + } + + @Override + public Class getValueClass() { + return Long.class; + } } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelStringType.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelStringType.java index 6f64ffd..b8fb663 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelStringType.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/settings/types/SettingsModelStringType.java @@ -1,7 +1,7 @@ package org.knime.scijava.commands.settings.types; import org.knime.core.node.defaultnodesettings.SettingsModelString; -import org.knime.scijava.commands.settings.SettingsModelTypePlugin; +import org.knime.scijava.commands.settings.SettingsModelType; import org.scijava.plugin.Plugin; /** @@ -9,38 +9,38 @@ * * @author Jonathan Hale (University of Konstanz) */ -@Plugin(type = SettingsModelTypePlugin.class) +@Plugin(type = SettingsModelType.class) public class SettingsModelStringType - implements SettingsModelTypePlugin { - - @Override - public SettingsModelString create(final String name, - final String defaultValue) { - if (defaultValue == null) { - return new SettingsModelString(name, ""); - } - return new SettingsModelString(name, defaultValue); - } - - @Override - public void setValue(final SettingsModelString settingsModel, - final String value) throws ClassCastException { - settingsModel.setStringValue(value); - } - - @Override - public String getValue(final SettingsModelString settingsModel) { - return settingsModel.getStringValue(); - } - - @Override - public Class getSettingsModelClass() { - return SettingsModelString.class; - } - - @Override - public Class getValueClass() { - return String.class; - } + implements SettingsModelType { + + @Override + public SettingsModelString create(final String name, + final String defaultValue) { + if (defaultValue == null) { + return new SettingsModelString(name, ""); + } + return new SettingsModelString(name, defaultValue); + } + + @Override + public void setValue(final SettingsModelString settingsModel, + final String value) throws ClassCastException { + settingsModel.setStringValue(value); + } + + @Override + public String getValue(final SettingsModelString settingsModel) { + return settingsModel.getStringValue(); + } + + @Override + public Class getSettingsModelClass() { + return SettingsModelString.class; + } + + @Override + public Class getValueClass() { + return String.class; + } } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/simplemapping/DefaultSimpleColumMappingService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/simplemapping/DefaultSimpleColumMappingService.java deleted file mode 100644 index e26ceac..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/simplemapping/DefaultSimpleColumMappingService.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.knime.scijava.commands.simplemapping; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.NoSuchElementException; - -import org.scijava.plugin.Plugin; -import org.scijava.service.AbstractService; - -@Plugin(type = SimpleColumnMappingService.class) -public class DefaultSimpleColumMappingService extends AbstractService - implements SimpleColumnMappingService { - - private final Map m_mappings = new HashMap<>(); - - @Override - public String getMappedColumn(final String input) { - return m_mappings.get(input); - } - - @Override - public String mappedColumn(final String input) - throws NoSuchElementException { - final String column = m_mappings.get(input); - if (column == null) { - throw new NoSuchElementException( - "Can't locate a mapping for input: " + input); - } - return column; - } - - @Override - public void setMappedColumn(final String input, final String column) { - m_mappings.put(input, column); - } - - @Override - public List getMappedInputs() { - final List mappedInputs = new ArrayList<>(); - for (final Entry item : m_mappings.entrySet()) { - if (item.getValue() != null) { - mappedInputs.add(item.getKey()); - } - } - return mappedInputs; - } - - @Override - public void clear() { - m_mappings.clear(); - } - - @Override - public String[] serialize() { - final List out = new ArrayList<>(); - - for (final Entry item : m_mappings.entrySet()) { - out.add(item.getKey() + "\n" + item.getValue()); - } - return out.toArray(new String[out.size()]); - } - - @Override - public void deserialize(final String[] serializedMappings) { - m_mappings.clear(); - for (final String s : serializedMappings) { - final String[] names = s.split("\n"); - - if (names.length != 2) { - // Invalid format! - throw new IllegalArgumentException( - "Unable to deserialize settings: invalid amount of input tokens!"); - } - // format is [0] module input name [1] column input name - m_mappings.put(names[0], names[1]); - } - } - -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/simplemapping/DefaultSimpleMappingPreProcessor.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/simplemapping/DefaultSimpleMappingPreProcessor.java deleted file mode 100644 index 0e13e70..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/simplemapping/DefaultSimpleMappingPreProcessor.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.knime.scijava.commands.simplemapping; - -import org.knime.core.data.DataCell; -import org.knime.core.data.DataRow; -import org.knime.core.data.DataTableSpec; -import org.knime.scijava.commands.converter.ConverterCacheService; -import org.knime.scijava.commands.io.InputDataRowService; -import org.knime.scijava.commands.process.KnimePreprocessor; -import org.scijava.Priority; -import org.scijava.log.LogService; -import org.scijava.module.Module; -import org.scijava.module.ModuleItem; -import org.scijava.module.process.AbstractPreprocessorPlugin; -import org.scijava.module.process.PreprocessorPlugin; -import org.scijava.plugin.Parameter; -import org.scijava.plugin.Plugin; - -@Plugin(type = PreprocessorPlugin.class, priority = Priority.HIGH_PRIORITY) -public class DefaultSimpleMappingPreProcessor extends AbstractPreprocessorPlugin - implements KnimePreprocessor { - - @Parameter - private SimpleColumnMappingService m_colMap; - @Parameter - private InputDataRowService m_inrow; - @Parameter - private LogService m_log; - @Parameter - private ConverterCacheService m_converters; - - @Override - public void process(final Module module) { - final DataTableSpec spec = m_inrow.getInputDataTableSpec(); - final DataRow row = m_inrow.getInputDataRow(); - - for (final String inputName : m_colMap.getMappedInputs()) { - - final String mappedColumn = m_colMap.getMappedColumn(inputName); - final ModuleItem input = module.getInfo().getInput(inputName); - - if (mappedColumn == null) { // Error or optional column - if (input.isRequired()) { - cancel("Couldn't find mapping for input \"" + inputName - + "\"! Mapping is invalid."); - } else { - // Input is optional and can be null - module.setInput(inputName, null); - module.setResolved(inputName, true); - return; - } - } - - DataCell cell = null; - - try { - cell = row.getCell(spec.findColumnIndex(mappedColumn)); - } catch (final IndexOutOfBoundsException e) { - // getColumnIndex() might return -1 or a index greater the - // column count - final String errortext = "Couldn't find column \"" + mappedColumn - + "\" which is mapped to input " + inputName + "."; - m_log.error(errortext, e); - cancel(errortext); - } - - // set the input and mark resolved - Object converted; - try { - converted = m_converters.convertToJava(cell, input.getType()); - } catch (final Exception e) { - throw new IllegalArgumentException( - "Could not process value for input: " + inputName - + ", the mapped column: \"" + mappedColumn - + "\" contains an illegal value: " - + e.getMessage()); - } - module.setInput(inputName, converted); - module.setResolved(inputName, true); - } - } - -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/simplemapping/SimpleColumnMappingService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/simplemapping/SimpleColumnMappingService.java deleted file mode 100644 index a6c6455..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/simplemapping/SimpleColumnMappingService.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.knime.scijava.commands.simplemapping; - -import java.util.List; -import java.util.NoSuchElementException; - -import org.scijava.service.Service; - -/** - * A simple service that stores a mapping between a modules input items and a - * columns of a table. - * - * @author Gabriel Einsdorf - */ -public interface SimpleColumnMappingService extends Service { - - /** - * return the column mapped to the input with the given name. - * - * @param input - * the name of the input - * @return the column mapped to the input or null if no column - * is mapped to it. - */ - public String getMappedColumn(String input); - - /** - * Equivalent to {@link #getMappedColumn(String)} but throws a - * {@link NoSuchElementException} if no mapping is available. - * - * @param input - * the name of the input - * @return the column mapped to the input. - * @throws NoSuchElementException - * if there is no mapping for that input. - */ - public String mappedColumn(String input); - - /** - * Map the name of the input to the column name. If the input was mapped to - * a another column, that mapping is replaced by the new one. - * - * @param input - * the name of the input - * @param column - * the mapped column - */ - public void setMappedColumn(String input, String column); - - /** - * @return A list of all inputs that are mapped - */ - public List getMappedInputs(); - - /** - * Remove all mappings from this service. - */ - public void clear(); - - /** - * @return a list which contains serialized mappings for storing in a - * settings model. - */ - public String[] serialize(); - - /** - * Reads the mappings from the given array, adding them to the Service. - * Replaces all current mappings in the Service. - * - * @param serializedMappings - * mappings serialized with {@link #serialize()}. - */ - public void deserialize(String[] serializedMappings); - -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/util/PrimitiveTypeUtils.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/util/PrimitiveTypeUtils.java deleted file mode 100644 index 7f82e61..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/util/PrimitiveTypeUtils.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.knime.scijava.commands.util; - -import java.util.HashMap; -import java.util.Map; - -public final class PrimitiveTypeUtils { - private static final Map, Class> m_primitvePluginTypes = new HashMap<>(); - - static { - m_primitvePluginTypes.put(byte.class, Byte.class); - m_primitvePluginTypes.put(short.class, Short.class); - m_primitvePluginTypes.put(double.class, Double.class); - m_primitvePluginTypes.put(int.class, Integer.class); - m_primitvePluginTypes.put(long.class, Long.class); - } - - private PrimitiveTypeUtils() { - // NB Utility class - } - - /** - * Checks if the given type is primitive, iff it is it will return the - * - * @param type - * the type to check if it is primitive - * @return the converted type iff it was primitive, otherwise the input type - */ - public static Class convertIfPrimitive(final Class type) { - final Class out = m_primitvePluginTypes.get(type); - return out != null ? out : type; - } -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/ColumnSelectKNIMEWidgetModel.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/ColumnSelectKNIMEWidgetModel.java deleted file mode 100644 index 0411b12..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/ColumnSelectKNIMEWidgetModel.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.knime.scijava.commands.widget; - -import java.util.List; - -import org.knime.core.node.defaultnodesettings.SettingsModel; -import org.knime.core.node.defaultnodesettings.SettingsModelString; -import org.knime.scijava.commands.settings.NodeDialogSettingsService; -import org.scijava.Context; -import org.scijava.module.Module; -import org.scijava.module.ModuleItem; -import org.scijava.plugin.Parameter; -import org.scijava.widget.DefaultWidgetModel; -import org.scijava.widget.InputPanel; - -public class ColumnSelectKNIMEWidgetModel extends DefaultWidgetModel - implements DialogInputWidgetModel { - - private final SettingsModelString m_model; - @Parameter - private NodeDialogSettingsService m_settingsService; - - public ColumnSelectKNIMEWidgetModel(final Context context, - final InputPanel inputPanel, final Module module, - final ModuleItem item, final List objectPool, - final SettingsModelString settingsModelString) { - super(context, inputPanel, module, item, objectPool); - m_model = settingsModelString; - } - - @Override - public void setValue(final Object value) { - // NB: SciJava will try to set the default value of the input as value - // during the constructor call of DefaultWidgetModel, we need to ignore - // this. - - if (value instanceof String) { - m_model.setStringValue((String) value); - } - } - - @Override - public SettingsModel getSettingsModel() { - return m_model; - } - - @Override - public void updateFromSettingsModel() { - // not needed, handled in the refresh method of the - // ColumnSelectionWidget - } -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/ColumnSelectionWidget.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/ColumnSelectionWidget.java new file mode 100644 index 0000000..d00d7e7 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/ColumnSelectionWidget.java @@ -0,0 +1,119 @@ +package org.knime.scijava.commands.widget; + +import java.awt.event.ItemEvent; +import java.util.Optional; + +import javax.swing.JPanel; + +import org.knime.core.data.DataTableSpec; +import org.knime.core.data.DataValue; +import org.knime.core.node.NotConfigurableException; +import org.knime.core.node.util.ColumnSelectionPanel; +import org.knime.core.node.util.DataValueColumnFilter; +import org.knime.scijava.commands.converter.KNIMEConverterService; +import org.knime.scijava.commands.settings.models.SettingsModelColumnSelection; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; +import org.scijava.ui.swing.widget.SwingInputWidget; +import org.scijava.widget.InputWidget; +import org.scijava.widget.WidgetModel; + +/** + * Widget for selecting a column to fill a certain module item. + * + * @author Christian Dietz, University of Konstanz + */ +@Plugin(type = InputWidget.class) +public class ColumnSelectionWidget extends SwingInputWidget { + + @Parameter + private KNIMEConverterService convCache; + + // Internal parameters + + private String selected; + + private ColumnSelectionPanel colBox; + + @SuppressWarnings("unchecked") + @Override + public void set(final WidgetModel model) { + super.set(model); + + // find columns that can be converted into the target value + final Optional> inputClass = convCache + .getMatchingInputValueClass(model.getItem().getType()); + + if (!inputClass.isPresent()) { + throw new IllegalArgumentException("No valid input available."); + } + + // optional columns get the option to select + final boolean isOptional = !model.getItem().isRequired(); + + colBox = new ColumnSelectionPanel(null, + new DataValueColumnFilter(inputClass.get()), isOptional); + + // set listener + colBox.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + selected = colBox.getSelectedColumn(); + updateModel(); + } + }); + + // set initial selection + + final DataTableSpec spec = getSpecFromModel(); + + if (spec != null) { + try { + colBox.update(getSpecFromModel(), null); + } catch (final NotConfigurableException e) { + throw new IllegalStateException(e); + } + } + selected = (String) model.getValue(); + } + + @Override + public String getValue() { + return selected; + } + + @Override + public JPanel getComponent() { + return colBox; + } + + @Override + public boolean supports(final WidgetModel model) { + return model instanceof SettingsModelWidgetModel + && (((SettingsModelWidgetModel) model) + .getSettingsModel() instanceof SettingsModelColumnSelection); + } + + @Override + public Class getComponentType() { + return JPanel.class; + } + + @Override + protected void doRefresh() { + try { + final DataTableSpec spec = getSpecFromModel(); + if (spec != null) { + colBox.update(getSpecFromModel(), (String) get().getValue()); + colBox.revalidate(); + colBox.repaint(); + } + } catch (final NotConfigurableException e) { + throw new IllegalStateException(e); + } + } + + private DataTableSpec getSpecFromModel() { + return ((SettingsModelColumnSelection) ((SettingsModelWidgetModel) get()) + .getSettingsModel()).getSpec(); + } +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/DataTypeSelectionWidget.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/DataTypeSelectionWidget.java new file mode 100644 index 0000000..23f1587 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/DataTypeSelectionWidget.java @@ -0,0 +1,113 @@ +package org.knime.scijava.commands.widget; + +import java.awt.event.ItemEvent; +import java.util.Collection; +import java.util.HashMap; + +import javax.swing.JComboBox; +import javax.swing.JPanel; + +import org.knime.core.data.DataCell; +import org.knime.core.data.convert.datacell.JavaToDataCellConverterFactory; +import org.knime.scijava.commands.converter.KNIMEConverterService; +import org.scijava.plugin.Parameter; +import org.scijava.plugin.Plugin; +import org.scijava.ui.swing.widget.SwingInputWidget; +import org.scijava.widget.InputWidget; +import org.scijava.widget.WidgetModel; + +/** + * Widget to select a DataType into which or from which to convert into the + * module item for which this widget is created. + * + * @author Christian Dietz, University of Konstanz + */ +@Plugin(type = InputWidget.class) +public class DataTypeSelectionWidget extends SwingInputWidget { + + @Parameter + private KNIMEConverterService cs; + + // Internal parameters + + private String selectedItem; + + private JPanel panel; + + private JComboBox comboBox; + + private final HashMap nameToClass; + + private final HashMap classToName; + + public DataTypeSelectionWidget() { + nameToClass = new HashMap<>(); + classToName = new HashMap<>(); + } + + @Override + public void set(final WidgetModel model) { + super.set(model); + + /* find converter factories for the module item */ + final Collection> sourceFacs = cs + .getMatchingFactories(model.getItem().getType()); + + if (sourceFacs.size() == 0) { + throw new IllegalArgumentException("No valid output available."); + } + + for (final JavaToDataCellConverterFactory fac : sourceFacs) { + final Class cellClass = fac.getDestinationType() + .getCellClass(); + nameToClass.put(cellClass.getSimpleName(), cellClass.getName()); + classToName.put(cellClass.getName(), cellClass.getSimpleName()); + } + + /* create a ComboBox for the converter factories */ + panel = new JPanel(); + comboBox = new JComboBox<>( + nameToClass.keySet().toArray(new String[nameToClass.size()])); + + // set listener which updates the widget model after an item is selected + comboBox.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + selectedItem = (String) comboBox.getSelectedItem(); + updateModel(); + } + }); + + // set initial selection + selectedItem = classToName.get(model.getValue()); + comboBox.setSelectedItem(selectedItem); + panel.add(comboBox); + } + + @Override + public String getValue() { + return nameToClass.get(selectedItem); + } + + @Override + public JPanel getComponent() { + return panel; + } + + @Override + public boolean supports(final WidgetModel model) { + return model instanceof SettingsModelWidgetModel + && model.getItem().isOutput(); + } + + @Override + public Class getComponentType() { + return JPanel.class; + } + + @Override + protected void doRefresh() { + comboBox.setSelectedItem(classToName.get(get().getValue())); + panel.revalidate(); + panel.repaint(); + } +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/DefaultKNIMEWidgetModel.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/DefaultKNIMEWidgetModel.java deleted file mode 100644 index 98f7fb2..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/DefaultKNIMEWidgetModel.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.knime.scijava.commands.widget; - -import java.util.List; - -import org.knime.core.node.defaultnodesettings.SettingsModel; -import org.knime.scijava.commands.settings.NodeDialogSettingsService; -import org.knime.scijava.commands.settings.NodeSettingsService; -import org.scijava.Context; -import org.scijava.module.Module; -import org.scijava.module.ModuleItem; -import org.scijava.plugin.Parameter; -import org.scijava.widget.DefaultWidgetModel; -import org.scijava.widget.InputPanel; - -/** - * Default implementation of DialogInputWidgetModel. - * - * @author Jonathan Hale (University of Konstanz) - */ -public class DefaultKNIMEWidgetModel extends DefaultWidgetModel - implements DialogInputWidgetModel { - - @Parameter - private NodeDialogSettingsService m_settingsService; - private final SettingsModel m_model; - - /** - * Constructor for generic input items. The used SettingsModel will be - * created by a {@link NodeSettingsService}. - * - * @see DialogInputWidgetModel - * @param context - * Context for the model - * @param inputPanel - * the panel - * @param module - * the module - * @param item - * the module item - * @param objectPool - * the ObejctPool - */ - public DefaultKNIMEWidgetModel(final Context context, - final InputPanel inputPanel, final Module module, - final ModuleItem item, final List objectPool) { - super(context, inputPanel, module, item, objectPool); - - m_model = m_settingsService.createAndAddSettingsModel(item, module, - false); - updateFromSettingsModel(); - } - - @Override - public void setValue(final Object value) { - // keep track of the values, update settings model - m_settingsService.setValue(getItem(), value); - } - - @Override - public SettingsModel getSettingsModel() { - return m_model; - } - - @Override - public void updateFromSettingsModel() { - super.setValue(m_settingsService.getValue(getItem())); - } -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/DialogInputWidgetModel.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/DialogInputWidgetModel.java deleted file mode 100644 index 0f143c8..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/DialogInputWidgetModel.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.knime.scijava.commands.widget; - -import org.knime.core.node.defaultnodesettings.SettingsModel; -import org.scijava.widget.WidgetModel; - -/** - * Since KNIME does not provide an interface for DialogComponents, this - * interface defines methods needed by DialogComponents for WidgetModels. Later - * the WidgetModel can be used by a DialogComponent subclass which wrapps this - * WidgetModel, calling exactly these defined methods. - * - * @author Jonathan Hale (University of Konstanz) - * - */ -public interface DialogInputWidgetModel extends WidgetModel { - - /** - * Get the underlying SettingsModel - * - * @return - */ - public SettingsModel getSettingsModel(); - - /** - * Update to reflect changes in SettingsModel. - */ - public void updateFromSettingsModel(); -} \ No newline at end of file diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/KNIMEWidgetService.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/KNIMEWidgetService.java index 7a0185e..67adae5 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/KNIMEWidgetService.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/KNIMEWidgetService.java @@ -33,106 +33,48 @@ import java.util.List; -import org.knime.core.node.defaultnodesettings.SettingsModelString; -import org.knime.scijava.commands.KNIMESciJavaConstants; -import org.knime.scijava.commands.settings.NodeSettingsService; -import org.knime.scijava.commands.simplemapping.SimpleColumnMappingService; import org.scijava.Priority; -import org.scijava.log.LogService; import org.scijava.module.Module; import org.scijava.module.ModuleItem; import org.scijava.plugin.AbstractWrapperService; -import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; -import org.scijava.widget.DefaultWidgetService; import org.scijava.widget.InputPanel; import org.scijava.widget.InputWidget; import org.scijava.widget.WidgetModel; import org.scijava.widget.WidgetService; /** - * KNIME service for managing available {@link InputWidget}s. + * Widget service which creates {@link SettingsModelWidgetModel}s. * - * @author Gabriel Einsdorf - * @author Jonathan Hale + * @author Christian Dietz, University of Konstanz */ @Plugin(type = WidgetService.class, priority = Priority.HIGH_PRIORITY) public class KNIMEWidgetService - extends AbstractWrapperService> - implements WidgetService { - - private static final String COLSELECT_KEY = KNIMESciJavaConstants.COLUMN_SELECT_KEY; - - private static final String DEFAULT_COL_KEY = KNIMESciJavaConstants.DEFAULT_COLUMN_KEY; - - @Parameter - private LogService m_log; - @Parameter - private SimpleColumnMappingService m_columnMapping; - @Parameter - private NodeSettingsService m_settings; - @Parameter - private DefaultWidgetService m_widgetService; - - // -- WidgetService methods -- - - @Override - public WidgetModel createModel(final InputPanel inputPanel, - final Module module, final ModuleItem item, - final List objectPool) { - - if ("true".equals(item.get(COLSELECT_KEY))) { - return new ColumnSelectKNIMEWidgetModel(getContext(), inputPanel, - module, item, objectPool, - new SettingsModelString(item.getName(), "")); - } - return new DefaultKNIMEWidgetModel(getContext(), inputPanel, module, - item, objectPool); - } - - // -- WrapperService methods -- - - @Override - public InputWidget create(final WidgetModel model) { - - // check if the creation of the column selection widget is forced. - final boolean createColSelect = "true" - .equals(model.getItem().get(COLSELECT_KEY)); - - InputWidget widget = null; - if (!createColSelect) { - widget = m_widgetService.create(model); - } - if (widget == null) { - // create column selection if selected or as fallback - widget = createColumnSelectionWidget(model); - } - - return widget; - } - - private InputWidget createColumnSelectionWidget( - final WidgetModel model) { - // check for default column - final String defaultCol = model.getItem().get(DEFAULT_COL_KEY); - final InputWidget widget = new KnimeColumnSelectionWidget(model, - context(), defaultCol); - return widget; - } - - // -- PTService methods -- - - @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Class> getPluginType() { - return (Class) InputWidget.class; - } - - // -- Typed methods -- - - @Override - public Class getType() { - return WidgetModel.class; - } + extends AbstractWrapperService> + implements WidgetService { + + // -- WidgetService methods -- + @Override + public WidgetModel createModel(final InputPanel inputPanel, + final Module module, final ModuleItem item, + final List objectPool) { + return new SettingsModelWidgetModel(getContext(), inputPanel, module, + item, objectPool); + } + + // -- PTService methods -- + + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Class> getPluginType() { + return (Class) InputWidget.class; + } + + // -- Typed methods -- + + @Override + public Class getType() { + return WidgetModel.class; + } } diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/KnimeColumnSelectionWidget.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/KnimeColumnSelectionWidget.java deleted file mode 100644 index 4d14cad..0000000 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/KnimeColumnSelectionWidget.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.knime.scijava.commands.widget; - -import java.awt.event.ItemEvent; -import java.util.Optional; - -import javax.swing.JPanel; - -import org.knime.core.data.DataValue; -import org.knime.core.node.NotConfigurableException; -import org.knime.core.node.util.ColumnSelectionPanel; -import org.knime.core.node.util.DataValueColumnFilter; -import org.knime.scijava.commands.converter.ConverterCacheService; -import org.knime.scijava.commands.io.InputDataRowService; -import org.knime.scijava.commands.settings.NodeDialogSettingsService; -import org.knime.scijava.commands.simplemapping.SimpleColumnMappingService; -import org.scijava.Context; -import org.scijava.log.LogService; -import org.scijava.plugin.Parameter; -import org.scijava.ui.swing.widget.SwingInputWidget; -import org.scijava.widget.WidgetModel; - -public class KnimeColumnSelectionWidget extends SwingInputWidget { - - private final String m_inputName; - private String m_selected; - private final ColumnSelectionPanel m_colbox; - - @Parameter - private ConverterCacheService m_converterCache; - @Parameter - private InputDataRowService m_irs; - @Parameter - private LogService m_log; - @Parameter - private SimpleColumnMappingService m_colMapping; - @Parameter - private NodeDialogSettingsService m_settings; - - public KnimeColumnSelectionWidget(final WidgetModel model, - final Context context, final String defaultColumn) { - context.inject(this); - - set(model); - m_inputName = model.getItem().getName(); - - // find columns that can be converted into the target value - final Optional> inputClass2 = m_converterCache - .getMatchingInputValueClass(model.getItem().getType()); - - if (!inputClass2.isPresent()) { - throw new IllegalArgumentException("No valid input available."); - } - - // optional columns get the option to select - final boolean isOptional = !model.getItem().isRequired(); - - m_colbox = new ColumnSelectionPanel(null, - new DataValueColumnFilter(inputClass2.get()), isOptional); - - // set listener - m_colbox.addItemListener(e -> { - if (e.getStateChange() == ItemEvent.SELECTED) { - updateState(model); - } - }); - - // set initial selection - if (defaultColumn == null || "".equals(defaultColumn)) { - try { - m_colbox.update(m_irs.getInputDataTableSpec(), null); - } catch (final NotConfigurableException e) { - m_log.warn(e); - } - updateState(model); // no default value set to first applicable - } else { - try { - m_colbox.update(m_irs.getInputDataTableSpec(), defaultColumn); - m_selected = defaultColumn; - m_colMapping.setMappedColumn(m_inputName, m_selected); - m_settings.setValue(model.getItem(), m_selected); - } catch (final NotConfigurableException e) { - m_log.warn("Could not select the column" + defaultColumn + e); - // TODO: Fail harder? - updateState(model); - } - } - } - - private void updateState(final WidgetModel model) { - m_selected = m_colbox.getSelectedColumn(); - m_colMapping.setMappedColumn(m_inputName, m_selected); - m_settings.setValue(model.getItem(), m_selected); - } - - @Override - public String getValue() { - return m_selected; - } - - @Override - public JPanel getComponent() { - return m_colbox; - } - - @Override - public boolean supports(final WidgetModel model) { - return true; - } - - @Override - public Class getComponentType() { - return JPanel.class; - } - - @Override - protected void doRefresh() { - try { - m_colbox.update(m_irs.getInputDataTableSpec(), getValue()); - } catch (final NotConfigurableException e) { - m_log.warn(e); - } - m_colbox.revalidate(); - m_colbox.repaint(); - } -} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/SettingsModelWidgetModel.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/SettingsModelWidgetModel.java new file mode 100644 index 0000000..378f183 --- /dev/null +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/SettingsModelWidgetModel.java @@ -0,0 +1,67 @@ +package org.knime.scijava.commands.widget; + +import java.util.List; + +import org.knime.core.node.defaultnodesettings.SettingsModel; +import org.knime.scijava.commands.settings.NodeSettingsService; +import org.scijava.Context; +import org.scijava.module.Module; +import org.scijava.module.ModuleItem; +import org.scijava.plugin.Parameter; +import org.scijava.widget.DefaultWidgetModel; +import org.scijava.widget.InputPanel; + +/** + * Widget model which stores its data in a settings model. + * + * @author Christian Dietz, University of Konstanz + */ +public class SettingsModelWidgetModel extends DefaultWidgetModel { + + @Parameter + private NodeSettingsService settingsService; + + private final SettingsModel settingsModel; + + /** + * Constructor for generic input items. The used SettingsModel will be + * created by a {@link NodeSettingsService}. + * + * @see DialogInputWidgetModel + * @param context + * Context for the model + * @param inputPanel + * the panel + * @param module + * the module + * @param item + * the module item + * @param objectPool + * the ObejctPool + */ + public SettingsModelWidgetModel(final Context context, + final InputPanel inputPanel, final Module module, + final ModuleItem item, final List objectPool) { + super(context, inputPanel, module, item, objectPool); + + // FIXME we should have a base64 encoded fall back SettinsModel for + // things we can not directly map from scijava to KNIME (easy wa) + settingsModel = settingsService.createSettingsModel(item); + } + + @Override + public Object getValue() { + return settingsService.getValue(settingsModel); + } + + @Override + public void setValue(final Object value) { + if (settingsModel != null) { + settingsService.setValue(settingsModel, value); + } + } + + public SettingsModel getSettingsModel() { + return settingsModel; + } +} diff --git a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/WidgetDialogComponent.java b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/WidgetDialogComponent.java index 5b7e028..4d427a9 100644 --- a/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/WidgetDialogComponent.java +++ b/org.knime.scijava.commands/src/org/knime/scijava/commands/widget/WidgetDialogComponent.java @@ -9,59 +9,56 @@ /** * A small DialogComponent wrapper around a {@link SwingInputWidget}. * - * @author Jonathan Hale + * @author Jonathan Hale, University of Konstanz */ public class WidgetDialogComponent extends DialogComponent { - /* the wrapped InputWidget */ - private final SwingInputWidget m_widget; - private final DialogInputWidgetModel m_model; + /* the wrapped InputWidget */ + private final SwingInputWidget m_widget; - /** - * Constructor. - * - * @param widget - * The {@link SwingInputWidget} to wrap - * @param model - * The model which contains the settings model for the - * InputWidget. - */ - public WidgetDialogComponent(final SwingInputWidget widget, - final DialogInputWidgetModel model) { - super(model.getSettingsModel()); + /** + * Constructor. + * + * @param widget + * The {@link SwingInputWidget} to wrap + * @param model + * The model which contains the settings model for the + * InputWidget. + */ + public WidgetDialogComponent(final SwingInputWidget widget, + final SettingsModelWidgetModel model) { + super(model.getSettingsModel()); - m_widget = widget; - m_model = model; + m_widget = widget; - updateComponent(); - } + updateComponent(); + } - @Override - protected void updateComponent() { - m_widget.refreshWidget(); - m_model.updateFromSettingsModel(); - } + @Override + protected void updateComponent() { + m_widget.refreshWidget(); + } - @Override - protected void validateSettingsBeforeSave() - throws InvalidSettingsException { - m_widget.updateModel(); - } + @Override + protected void validateSettingsBeforeSave() + throws InvalidSettingsException { + m_widget.updateModel(); + } - @Override - protected void checkConfigurabilityBeforeLoad(final PortObjectSpec[] specs) - throws NotConfigurableException { - /* nothing to do. */ - } + @Override + protected void checkConfigurabilityBeforeLoad(final PortObjectSpec[] specs) + throws NotConfigurableException { + /* nothing to do. */ + } - @Override - protected void setEnabledComponents(final boolean enabled) { - m_widget.getComponent().setEnabled(enabled); - } + @Override + protected void setEnabledComponents(final boolean enabled) { + m_widget.getComponent().setEnabled(enabled); + } - @Override - public void setToolTipText(final String text) { - m_widget.getComponent().setToolTipText(text); - } + @Override + public void setToolTipText(final String text) { + m_widget.getComponent().setToolTipText(text); + } } diff --git a/org.knime.scijava.core/src/org/knime/scijava/core/ResourceAwareClassLoader.java b/org.knime.scijava.core/src/org/knime/scijava/core/ResourceAwareClassLoader.java index a530236..25c9f3e 100644 --- a/org.knime.scijava.core/src/org/knime/scijava/core/ResourceAwareClassLoader.java +++ b/org.knime.scijava.core/src/org/knime/scijava/core/ResourceAwareClassLoader.java @@ -212,6 +212,10 @@ private static void safeAdd(final Set urls, final URL urlToAdd) { } catch (IOException e) { // ignore } + + if(urlToAdd.toString().contains("knip.io")){ + System.out.println("A"); + } // no duplicate found, we can safely add this url. urls.add(urlToAdd);