use of org.knime.core.node.port.PortObjectSpec in project knime-core by knime.
the class Node method setOutPortObjects.
/**
* Called after execute in order to put the computed result into the
* outports. It will do a sequence of sanity checks whether the argument
* is valid (non-null, correct type, etc.)
* @param newOutData The computed output data
* @param tolerateNullOutports used e.g. when loop is continued (outports may not yet be available)
* @param tolerateDifferentSpecs used e.g. when re-executing a node (table may be different from configure)
* @return Whether that is successful (false in case of incompatible port objects)
*/
private boolean setOutPortObjects(final PortObject[] newOutData, final boolean tolerateNullOutports, final boolean tolerateDifferentSpecs) {
CheckUtils.checkArgumentNotNull(newOutData, "Port object array is null");
if (newOutData.length != getNrOutPorts()) {
throw new IndexOutOfBoundsException("Array is expected to be of " + "length " + getNrOutPorts() + ": " + newOutData.length);
}
// check for compatible output PortObjects
for (int i = 0; i < newOutData.length; i++) {
PortType thisType = m_outputs[i].type;
if (newOutData[i] == null && !tolerateNullOutports) {
createErrorMessageAndNotify("Output at port " + i + " is null");
return false;
}
if (newOutData[i] != null) {
if (newOutData[i] instanceof InactiveBranchPortObject) {
// allow PO coming from inactive branch
// TODO ensure model was skipped during configure?
} else if (!thisType.getPortObjectClass().isInstance(newOutData[i])) {
createErrorMessageAndNotify("Invalid output port object at port " + i);
LOGGER.error(" (Wanted: " + thisType.getPortObjectClass().getName() + ", " + "actual: " + newOutData[i].getClass().getName() + ")");
return false;
}
PortObjectSpec spec;
try {
spec = newOutData[i].getSpec();
} catch (Throwable t) {
createErrorMessageAndNotify("PortObject \"" + newOutData[i].getClass().getName() + "\" threw " + t.getClass().getSimpleName() + " on #getSpec() ", t);
return false;
}
if (spec == null) {
createErrorMessageAndNotify("Implementation Error: PortObject \"" + newOutData[i].getClass().getName() + "\" must not" + " have null spec (output port " + i + ").");
return false;
}
}
}
for (int p = 0; p < getNrOutPorts(); p++) {
if (newOutData[p] instanceof BufferedDataTable) {
BufferedDataTable thisTable = (BufferedDataTable) newOutData[p];
DataTableSpec portSpec = (DataTableSpec) (m_outputs[p].spec);
DataTableSpec newPortSpec = thisTable.getDataTableSpec();
if ((portSpec != null) && !tolerateDifferentSpecs) {
if (!portSpec.equalStructure(newPortSpec)) {
String errorMsg = "DataSpec generated by configure does not match spec after execution.";
LOGGER.coding(errorMsg);
createErrorMessageAndNotify(errorMsg);
}
}
BufferedDataTable t = thisTable;
t.setOwnerRecursively(this);
m_outputs[p].object = t;
m_outputs[p].summary = t.getSummary();
m_outputs[p].spec = newPortSpec;
} else {
m_outputs[p].object = newOutData[p];
if (newOutData[p] != null) {
m_outputs[p].spec = newOutData[p].getSpec();
m_outputs[p].summary = newOutData[p].getSummary();
} else {
m_outputs[p].summary = null;
}
}
}
return true;
}
use of org.knime.core.node.port.PortObjectSpec in project knime-core by knime.
the class Node method configure.
/**
* Allows passing an object that may modify the specs created by the
* {@link NodeModel}, for example in case the node is wrapped and the
* output is modified.
*
* @param rawInSpecs table specs from the predecessors
* @param configureHelper object called after node model calculated output
* specs
* @return true if configure finished successfully.
* @noreference This method is not intended to be referenced by clients.
*/
public boolean configure(final PortObjectSpec[] rawInSpecs, final NodeConfigureHelper configureHelper) {
boolean success = false;
LOGGER.assertLog(NodeContext.getContext() != null, "No node context available, please check call hierarchy and fix it");
synchronized (m_configureLock) {
// reset message object
clearNodeMessageAndNotify();
// copy input port object specs, ignoring the 0-variable port:
PortObjectSpec[] inSpecs = Arrays.copyOfRange(rawInSpecs, 1, rawInSpecs.length);
// clean output spec
for (int p = 0; p < m_outputs.length; p++) {
// update data table spec
m_outputs[p].spec = null;
}
PortObjectSpec[] newOutSpec = new PortObjectSpec[getNrOutPorts() - 1];
try {
// check the inspecs against null
for (int i = 0; i < inSpecs.length; i++) {
if (inSpecs[i] == null) {
if (m_inputs[i + 1].getType().isOptional()) {
// ignore, unconnected optional input
} else {
return false;
}
// TODO: did we really need a warning here??
// throw new InvalidSettingsException(
// "Node is not executable until all predecessors "
// + "are configured and/or executed.");
}
}
// check if the node is part of a skipped branch and return
// appropriate specs without actually configuring the node.
// Note that we must also check the incoming variable port!
boolean isInactive = false;
if (!isInactiveBranchConsumer()) {
for (int i = 0; i < rawInSpecs.length; i++) {
if (rawInSpecs[i] instanceof InactiveBranchPortObjectSpec) {
isInactive = true;
break;
}
}
} else {
FlowLoopContext flc = getFlowObjectStack().peek(FlowLoopContext.class);
if (flc != null && flc.isInactiveScope()) {
isInactive = true;
}
}
if (isInactive) {
for (int j = 0; j < m_outputs.length; j++) {
m_outputs[j].spec = InactiveBranchPortObjectSpec.INSTANCE;
}
if (success) {
LOGGER.debug("Configure skipped. (" + getName() + " in inactive branch.)");
}
return true;
}
if (configureHelper != null) {
configureHelper.preConfigure();
}
// call configure model to create output table specs
// guaranteed to return non-null, correct-length array
newOutSpec = invokeNodeModelConfigure(inSpecs);
if (configureHelper != null) {
newOutSpec = configureHelper.postConfigure(inSpecs, newOutSpec);
}
// find out if we are in the middle of executing a loop and this is a LoopEnd node
boolean isIntermediateRunningLoop = false;
if (isModelCompatibleTo(LoopEndNode.class)) {
if ((getLoopContext() != null) && !getPauseLoopExecution()) {
FlowLoopContext flc = m_model.getFlowObjectStack().peek(FlowLoopContext.class);
if ((flc != null) && (flc.getIterationIndex() > 0)) {
// don't treat first iteration as "in the middle":
isIntermediateRunningLoop = true;
}
}
}
if (!isIntermediateRunningLoop) {
// update data table specs
for (int p = 0; p < newOutSpec.length; p++) {
m_outputs[p + 1].spec = newOutSpec[p];
}
} else {
// on the loop end node (avoids costly configure calls on remainder of workflow).
for (int p = 0; p < newOutSpec.length; p++) {
if (newOutSpec[p] instanceof DataTableSpec) {
// remove domain before assigning spec to outputs
DataTableSpecCreator dtsCreator = new DataTableSpecCreator((DataTableSpec) newOutSpec[p]);
dtsCreator.dropAllDomains();
m_outputs[p + 1].spec = dtsCreator.createSpec();
} else {
// no domain to clean in PortObjectSpecs
m_outputs[p + 1].spec = newOutSpec[p];
}
}
}
m_outputs[0].spec = FlowVariablePortObjectSpec.INSTANCE;
success = true;
} catch (InvalidSettingsException ise) {
Throwable cause = ise.getCause();
if (cause == null) {
createWarningMessageAndNotify(ise.getMessage());
} else {
createWarningMessageAndNotify(ise.getMessage(), ise);
}
} catch (Throwable t) {
String error = "Configure failed (" + t.getClass().getSimpleName() + "): " + t.getMessage();
createErrorMessageAndNotify(error, t);
}
}
if (success) {
LOGGER.debug("Configure succeeded. (" + this.getName() + ")");
}
return success;
}
use of org.knime.core.node.port.PortObjectSpec in project knime-core by knime.
the class NodeModel method configureModel.
/**
* This function is called when something changes that could affect the
* output <code>DataTableSpec</code> elements. E.g. after a reset,
* execute, (dis-)connect, and object creation (model instantiation).
* <p>
* The function calls <code>#configure()</code> to receive the updated
* output DataTableSpecs, if the model is not executed yet. After execution
* the DataTableSpecs are simply taken from the output DataTables.
*
* @param inSpecs An array of input <code>DataTableSpec</code> elements,
* either the array or each of its elements can be
* <code>null</code>.
* @return An array where each element indicates if the outport has changed.
* @throws InvalidSettingsException if the current settings don't go along
* with the table specs
*/
final PortObjectSpec[] configureModel(final PortObjectSpec[] inSpecs) throws InvalidSettingsException {
assert inSpecs.length == getNrInPorts();
setWarningMessage(null);
PortObjectSpec[] copyInSpecs = new PortObjectSpec[getNrInPorts()];
PortObjectSpec[] newOutSpecs;
System.arraycopy(inSpecs, 0, copyInSpecs, 0, inSpecs.length);
// Rather empty ones than null
for (int i = 0; i < copyInSpecs.length; i++) {
if (copyInSpecs[i] == null && BufferedDataTable.TYPE.equals(m_inPortTypes[i]) && !m_inPortTypes[i].isOptional()) {
// only mimic empty table for real table connections
copyInSpecs[i] = new DataTableSpec();
}
// only weak port compatibility check during connect
// (model reader can be connected to any model port)
// complain if actual types are incompatible.
Class<? extends PortObjectSpec> expected = m_inPortTypes[i].getPortObjectSpecClass();
if (// i.e. skip only "optional and not connected"
copyInSpecs[i] != null && !expected.isAssignableFrom(copyInSpecs[i].getClass()) && !(copyInSpecs[i] instanceof InactiveBranchPortObjectSpec)) {
StringBuilder b = new StringBuilder("Incompatible port spec");
if (copyInSpecs.length > 1) {
b.append(" at port ").append(i);
}
b.append(", expected: ").append(expected.getSimpleName());
b.append(", actual: ").append(copyInSpecs[i].getClass().getSimpleName());
throw new InvalidSettingsException(b.toString());
}
}
// CALL CONFIGURE
newOutSpecs = configure(copyInSpecs);
if (newOutSpecs == null) {
newOutSpecs = new PortObjectSpec[getNrOutPorts()];
}
// check output object spec length
if (newOutSpecs.length != getNrOutPorts()) {
m_logger.error("Output spec-array length invalid: " + newOutSpecs.length + " <> " + getNrOutPorts());
newOutSpecs = new PortObjectSpec[getNrOutPorts()];
}
return newOutSpecs;
}
use of org.knime.core.node.port.PortObjectSpec in project knime-core by knime.
the class DialogComponentColumnFilter method updateComponent.
/**
* {@inheritDoc}
*/
@Override
protected void updateComponent() {
// update component only if content is out of sync
final SettingsModelFilterString filterModel = (SettingsModelFilterString) getModel();
final Set<String> compIncl = m_columnFilter.getIncludedColumnSet();
final Set<String> compExcl = m_columnFilter.getExcludedColumnSet();
final boolean compKeepAll = m_columnFilter.isKeepAllSelected();
final Set<String> modelIncl = new LinkedHashSet<String>(filterModel.getIncludeList());
final Set<String> modelExcl = new LinkedHashSet<String>(filterModel.getExcludeList());
final boolean modelKeepAll = filterModel.isKeepAllSelected();
boolean update = (compIncl.size() != modelIncl.size()) || (compExcl.size() != modelExcl.size() || compKeepAll != modelKeepAll);
if (!update) {
// update if the current spec and the spec we last updated with
// are different
final PortObjectSpec currPOSpec = getLastTableSpec(m_inPortIndex);
if (currPOSpec == null) {
update = false;
} else {
if (!(currPOSpec instanceof DataTableSpec)) {
throw new RuntimeException("Wrong type of PortObject for" + " ColumnFilterPanel, expecting DataTableSpec!");
}
final DataTableSpec currSpec = (DataTableSpec) currPOSpec;
update = (!currSpec.equalStructure(m_specInFilter));
}
}
if (!update) {
// one way check, because size is equal
update = !modelIncl.containsAll(compIncl);
}
if (!update) {
// one way check, because size is equal
update = !modelExcl.containsAll(compExcl);
}
if (update) {
m_specInFilter = (DataTableSpec) getLastTableSpec(m_inPortIndex);
if (m_specInFilter == null) {
// the component doesn't take a null spec. Create an empty one
m_specInFilter = new DataTableSpec();
}
m_columnFilter.update(m_specInFilter, filterModel.getIncludeList(), filterModel.getExcludeList(), m_inclUnknown);
m_columnFilter.setKeepAllSelected(modelKeepAll);
}
// also update the enable status
setEnabledComponents(filterModel.isEnabled());
}
use of org.knime.core.node.port.PortObjectSpec in project knime-core by knime.
the class FileNodePersistor method loadPorts.
/**
* @noreference
* @nooverride
*/
void loadPorts(final Node node, final ExecutionMonitor exec, final NodeSettingsRO settings, final Map<Integer, BufferedDataTable> loadTblRep, final HashMap<Integer, ContainerTable> tblRep, final FileStoreHandlerRepository fileStoreHandlerRepository) throws IOException, InvalidSettingsException, CanceledExecutionException {
final int nrOutPorts = node.getNrOutPorts();
if (getLoadVersion().isOlderThan(FileWorkflowPersistor.LoadVersion.V200)) {
// skip flow variables port (introduced in v2.2)
for (int i = 1; i < nrOutPorts; i++) {
int oldIndex = getOldPortIndex(i);
ExecutionMonitor execPort = exec.createSubProgress(1.0 / nrOutPorts);
exec.setMessage("Port " + oldIndex);
PortType type = node.getOutputType(i);
boolean isDataPort = BufferedDataTable.class.isAssignableFrom(type.getPortObjectClass());
if (m_isConfigured) {
PortObjectSpec spec = loadPortObjectSpec(node, settings, oldIndex);
setPortObjectSpec(i, spec);
}
if (m_isExecuted) {
PortObject object;
if (isDataPort) {
object = loadBufferedDataTable(node, settings, execPort, loadTblRep, oldIndex, tblRep, fileStoreHandlerRepository);
} else {
throw new IOException("Can't restore model ports of " + "old 1.x workflows. Execute node again.");
}
String summary = object != null ? object.getSummary() : null;
setPortObject(i, object);
setPortObjectSummary(i, summary);
}
execPort.setProgress(1.0);
}
} else {
if (nrOutPorts == 1) {
// only the mandatory flow variable port
return;
}
NodeSettingsRO portsSettings = loadPortsSettings(settings);
exec.setMessage("Reading outport data");
for (String key : portsSettings.keySet()) {
NodeSettingsRO singlePortSetting = portsSettings.getNodeSettings(key);
ExecutionMonitor subProgress = exec.createSubProgress(1 / (double) nrOutPorts);
int index = loadPortIndex(singlePortSetting);
if (index < 0 || index >= nrOutPorts) {
throw new InvalidSettingsException("Invalid outport index in settings: " + index);
}
String portDirN = singlePortSetting.getString("port_dir_location");
if (portDirN != null) {
ReferencedFile portDir = new ReferencedFile(getNodeDirectory(), portDirN);
subProgress.setMessage("Port " + index);
loadPort(node, portDir, singlePortSetting, subProgress, index, loadTblRep, tblRep, fileStoreHandlerRepository);
}
subProgress.setProgress(1.0);
}
}
}
Aggregations