Contains all classes needed to implement a new node in the workflow.
It contains all classes that will be instantiated when a new node is plugged
into the workflow. And it
provides abstract classes {@link org.knime.core.node.NodeModel}, {@link
org.knime.core.node.NodeView} and {@link org.knime.core.node.NodeDialogPane}
that must be extended when a new type of node is implemented.
Nodes are connected to each other through their ports. Data or models are
exchanged over these connections. Nodes implement a certain task, like reading
in data, analyzing, displaying, writing out data, etc. The final class {@link
org.knime.core.node.Node}, together with the abstract {@link
org.knime.core.node.NodeModel}, {@link org.knime.core.node.NodeDialog}, and
{@link org.knime.core.node.NodeView} do most of the infrastructural work that is
needed to connect a new node in the workflow.
Nodes have different states:
not executable
,
executable
, or
executed
. A node is not executable until all ports are connected to predecessor nodes
and all required parameters are set (which depends on the task of the specific
node model). If a node is executable the execution can be invoked, causing the
node to read in the {@link org.knime.core.data.DataTable}s (see the {@link
org.knime.core.data data} package) and models from its inputs, to do what ever
it is supposed to do with the data and/or models (again depending on the
specific incarnation of the node model), and to provide new {@link
org.knime.core.data.DataTable}s at its output ports. If execution finishes
successfully the node is in the state
executed
.
Nodes should implement the following Model-View-Controller concept. The model
computes and stores the content of the node. A view provides a view to the
actual state of the model; it doesn't change the model. There could be more than
one view, providing different kinds of views onto the model. The controller is
the part that modifies the model. In our case there is more than one controller.
The {@link org.knime.core.node.NodeDialogPane} implements a controller that sets
the parameters in the {@link org.knime.core.node.NodeModel} before it can be
executed.
The communication between the dialog and the model is happening through {@link
org.knime.core.node.NodeSettings NodeSettings} objects. The dialog will read the
current settings of the model before opening, and all user settings will be
transfered back into the model (as a side effect, you may not store settings for
a node model that are not handled by the dialog, because the). For this, the
derived dialog and model must implement load and save settings methods, the
model will have in addition a validate settings method. The transfer of these
objects is implemented in the abstract classes.
Things a new Node implementation (here called
MyNode
...) must provide:
- a new class
MyNodeModel
derived from {@link org.knime.core.node.NodeModel NodeModel} representing the
model of a node. The MyNodeModel
must implement at least:
- a method
execute(...)
,
which performs the actual task of the node, invoked during executeNode()
.
It gets the {@link org.knime.core.data.DataTable}s from the inputs of the node
as parameters and must provide {@link org.knime.core.data.DataTable}s for the
outputs of the node as result.
- a method
configure(...)
,
which provides meta information about the {@link
org.knime.core.data.DataTable}s that will be generated during execution - at a
time before execution. Some nodes can provide information upfront about the
structure of the {@link org.knime.core.data.DataTable}s they will create,
either after parameters are set or after they've received information about
the incoming {@link org.knime.core.data.DataTable}s. They should return this
meta information in {@link org.knime.core.data.DataTableSpec}s as a result of
this method. The others just return null
. In addition, this
method must indicate whether the model received all settings and is ready to
be executed.
- a method
saveSettingsTo(...)
that will write out the current user settings of the model into a {@link
org.knime.core.node.NodeSettings} object.
- a method
validateSettings(...)
which checks a settings object telling if the settings in there are complete
and consistent.
- a method
loadValidatedSettings(...)
which sets new values in the internal settings of the model from a valid
settings object.
- a method
reset()
that clears out all internal data depending on or derived from any incoming
data from predecessors.
- a method
saveInternalSettings(...)
which must save all internal data derived from the input data (that is
basically the data cleared during reset()
) onto disk.
- a method
loadInternalSettings(...)
that must be able to read back the data written during saveInternalSettings(...)
.
After loadInternalSettings(...)
the model must be in the same
state as after execute. loadInternalSettings(...)
is called when
loading a workflow to re-establish the state of all nodes before closing the
flow.
- a new class
MyNodeFactory
derived from {@link org.knime.core.node.NodeFactory NodeFactory}, that returns
new instances of MyNodeModel
, MyNodeView
, and MyNodeDialog
,
if implemented. The instances created by one factory must work together and
form the Model-View-Controller concept for that particular incarnation of a
node. NodeView
and NodeDialog
are optional (the
factory can return null
), a NodeModel must always be provided.
- in addition a file
MyNodeFactory.xml
must be created, which contains the description of the node, its
functionality, its ports, views, and dialog options. The information will be
read from the factory and can be retrieved from there. Please read here for the content and structure
of the NodeFactory.xml file.
In addition, a node should think about providing a {@link
org.knime.core.node.property.hilite.HiLiteHandler HiLiteHandler}. These are
independent and separate instances storing the hilite status for each data point
in a {@link org.knime.core.data.DataTable}. Any (part of a) node can ask a
hilite handler for this property of a given row, and it can also register as
listener to be notified of any change in the properties of any row. On the other
hand each node can set new properties in a handler and can expect these
properties to show in all nodes listening.
New hilite handler instances must be created by nodes that create {@link
org.knime.core.data.DataTable}s with new {@link org.knime.core.data.RowKey}s at
their outputs. In the method {@link
org.knime.core.node.NodeModel#getOutHiLiteHandler(int)} the model decides for
each output port which {@link org.knime.core.node.property.hilite.HiLiteHandler
HiLiteHandler} goes along with the {@link org.knime.core.data.DataTable}
provided at this output port. The default implementation in the abstract {@link
org.knime.core.node.NodeModel} just passes along the {@link
org.knime.core.node.property.hilite.HiLiteHandler HiLiteHandler} it receives at
input port "0". If it has no input port, it will instantiate a new {@link
org.knime.core.node.property.hilite.HiLiteHandler HiLiteHandler}, as it must be
the beginning of a data flow then. There are default hilite handler
implementations (see package {@link org.knime.core.data.property property}) that
can be used when a new handler instance is needed.