Search in sources :

Example 1 with NodeExecutionResult

use of org.knime.core.node.workflow.execresult.NodeExecutionResult in project knime-core by knime.

the class Node method createNodeExecutionResult.

/**
 * Creates an execution result containing all calculated values in a
 * execution. The returned value is suitable to be used in
 * {@link #loadDataAndInternals(
 * NodeContentPersistor, ExecutionMonitor, LoadResult)}.
 * If this node is not executed, it will assign null values to the fields
 * in the returned execution result.
 * @param exec For progress information.
 * @return A new execution result containing the values being calculated.
 * @throws CanceledExecutionException If canceled
 */
public NodeExecutionResult createNodeExecutionResult(final ExecutionMonitor exec) throws CanceledExecutionException {
    NodeExecutionResult result = new NodeExecutionResult();
    result.setWarningMessage(m_model.getWarningMessage());
    if (hasContent()) {
        File internTempDir;
        try {
            internTempDir = FileUtil.createTempDir("knime_node_internDir");
            exec.setMessage("Saving internals");
            saveInternals(internTempDir, exec.createSubProgress(0.0));
            result.setNodeInternDir(new ReferencedFile(internTempDir));
        } catch (IOException ioe) {
            LOGGER.error("Unable to save internals", ioe);
        }
    }
    if (m_internalHeldPortObjects != null) {
        PortObject[] internalHeldPortObjects = Arrays.copyOf(m_internalHeldPortObjects, m_internalHeldPortObjects.length);
        result.setInternalHeldPortObjects(internalHeldPortObjects);
    }
    PortObject[] pos = new PortObject[getNrOutPorts()];
    PortObjectSpec[] poSpecs = new PortObjectSpec[getNrOutPorts()];
    for (int i = 0; i < pos.length; i++) {
        PortObject po = getOutputObject(i);
        if (po != null) {
            pos[i] = po;
            poSpecs[i] = po.getSpec();
        }
    }
    result.setPortObjects(pos);
    result.setPortObjectSpecs(poSpecs);
    // Add the outgoing flow variables to the execution result
    FlowObjectStack outgoingStack = m_model.getOutgoingFlowObjectStack();
    List<FlowVariable> nodeFlowVars = outgoingStack.getAvailableFlowVariables().values().stream().filter(f -> f.getScope().equals(FlowVariable.Scope.Flow)).collect(Collectors.toList());
    // the bottom most element should remain at the bottom of the stack
    Collections.reverse(nodeFlowVars);
    result.setFlowVariables(nodeFlowVars);
    return result;
}
Also used : WizardNode(org.knime.core.node.wizard.WizardNode) ScopeEndNode(org.knime.core.node.workflow.ScopeEndNode) NodeType(org.knime.core.node.NodeFactory.NodeType) Arrays(java.util.Arrays) NodeCreationConfiguration(org.knime.core.node.context.NodeCreationConfiguration) BufferedInputStream(java.io.BufferedInputStream) RowKey(org.knime.core.data.RowKey) NodeMessageEvent(org.knime.core.node.workflow.NodeMessageEvent) ReferencedFile(org.knime.core.internal.ReferencedFile) FileStoreUtil(org.knime.core.data.filestore.FileStoreUtil) IWriteFileStoreHandler(org.knime.core.data.filestore.internal.IWriteFileStoreHandler) IDataRepository(org.knime.core.data.IDataRepository) InteractiveNode(org.knime.core.node.interactive.InteractiveNode) StringUtils(org.apache.commons.lang3.StringUtils) ExecutionEnvironment(org.knime.core.node.workflow.ExecutionEnvironment) ByteArrayInputStream(java.io.ByteArrayInputStream) Map(java.util.Map) ModifiableNodeCreationConfiguration(org.knime.core.node.context.ModifiableNodeCreationConfiguration) FlowTryCatchContext(org.knime.core.node.workflow.FlowTryCatchContext) ContainerTable(org.knime.core.data.container.ContainerTable) InactiveBranchPortObjectSpec(org.knime.core.node.port.inactive.InactiveBranchPortObjectSpec) PortType(org.knime.core.node.port.PortType) PrintWriter(java.io.PrintWriter) PortObjectZipOutputStream(org.knime.core.node.port.PortObjectZipOutputStream) VirtualSubNodeInputNodeModel(org.knime.core.node.workflow.virtual.subnode.VirtualSubNodeInputNodeModel) Set(java.util.Set) CopyOnWriteArraySet(java.util.concurrent.CopyOnWriteArraySet) Collectors(java.util.stream.Collectors) InterruptibleNodeModel(org.knime.core.node.interrupt.InterruptibleNodeModel) List(java.util.List) HiLiteHandler(org.knime.core.node.property.hilite.HiLiteHandler) Optional(java.util.Optional) InteractiveNodeFactoryExtension(org.knime.core.node.interactive.InteractiveNodeFactoryExtension) CheckUtils(org.knime.core.node.util.CheckUtils) PortObject(org.knime.core.node.port.PortObject) PortObjectZipInputStream(org.knime.core.node.port.PortObjectZipInputStream) NodeMessage(org.knime.core.node.workflow.NodeMessage) Rectangle(java.awt.Rectangle) FileStorePortObject(org.knime.core.data.filestore.FileStorePortObject) NodeMessageListener(org.knime.core.node.workflow.NodeMessageListener) FlowVariablePortObject(org.knime.core.node.port.flowvariable.FlowVariablePortObject) ByteArrayOutputStream(java.io.ByteArrayOutputStream) ValueControlledDialogPane(org.knime.core.node.dialog.ValueControlledDialogPane) DataTableSpec(org.knime.core.data.DataTableSpec) LoopEndNode(org.knime.core.node.workflow.LoopEndNode) NodeExecutionJobManagerPool(org.knime.core.node.util.NodeExecutionJobManagerPool) FlowVariable(org.knime.core.node.workflow.FlowVariable) ArrayUtils(org.apache.commons.lang3.ArrayUtils) SplitType(org.knime.core.node.workflow.NodeContainer.NodeContainerSettings.SplitType) AtomicReference(java.util.concurrent.atomic.AtomicReference) PortObjectSpecZipInputStream(org.knime.core.node.port.PortObjectSpecZipInputStream) ArrayList(java.util.ArrayList) PortTypeRegistry(org.knime.core.node.port.PortTypeRegistry) CredentialsProvider(org.knime.core.node.workflow.CredentialsProvider) PortUtil(org.knime.core.node.port.PortUtil) ViewUtils(org.knime.core.node.util.ViewUtils) LoadResult(org.knime.core.node.workflow.WorkflowPersistor.LoadResult) InactiveBranchPortObject(org.knime.core.node.port.inactive.InactiveBranchPortObject) LinkedHashSet(java.util.LinkedHashSet) FlowObjectStack(org.knime.core.node.workflow.FlowObjectStack) ScopeStartNode(org.knime.core.node.workflow.ScopeStartNode) StringWriter(java.io.StringWriter) DeferredFileOutputStream(org.apache.commons.io.output.DeferredFileOutputStream) InteractiveView(org.knime.core.node.interactive.InteractiveView) PortObjectSpec(org.knime.core.node.port.PortObjectSpec) FlowScopeContext(org.knime.core.node.workflow.FlowScopeContext) IOException(java.io.IOException) InactiveBranchConsumer(org.knime.core.node.port.inactive.InactiveBranchConsumer) FileInputStream(java.io.FileInputStream) PortObjectSpecZipOutputStream(org.knime.core.node.port.PortObjectSpecZipOutputStream) WizardNodeFactoryExtension(org.knime.core.node.wizard.WizardNodeFactoryExtension) NodeContext(org.knime.core.node.workflow.NodeContext) File(java.io.File) ViewContent(org.knime.core.node.interactive.ViewContent) KnowsRowCountTable(org.knime.core.node.BufferedDataTable.KnowsRowCountTable) Element(org.w3c.dom.Element) NodeExecutionResult(org.knime.core.node.workflow.execresult.NodeExecutionResult) LoopStartNode(org.knime.core.node.workflow.LoopStartNode) NodeID(org.knime.core.node.workflow.NodeID) DataContainerException(org.knime.core.data.container.DataContainerException) WorkflowDataRepository(org.knime.core.node.workflow.WorkflowDataRepository) FileUtil(org.knime.core.util.FileUtil) DataTableSpecCreator(org.knime.core.data.DataTableSpecCreator) IFileStoreHandler(org.knime.core.data.filestore.internal.IFileStoreHandler) ValueControlledNode(org.knime.core.node.dialog.ValueControlledNode) FlowVariablePortObjectSpec(org.knime.core.node.port.flowvariable.FlowVariablePortObjectSpec) FlowLoopContext(org.knime.core.node.workflow.FlowLoopContext) Collections(java.util.Collections) InputStream(java.io.InputStream) PortObjectHolder(org.knime.core.node.port.PortObjectHolder) NodeExecutionResult(org.knime.core.node.workflow.execresult.NodeExecutionResult) FlowObjectStack(org.knime.core.node.workflow.FlowObjectStack) IOException(java.io.IOException) ReferencedFile(org.knime.core.internal.ReferencedFile) InactiveBranchPortObjectSpec(org.knime.core.node.port.inactive.InactiveBranchPortObjectSpec) PortObjectSpec(org.knime.core.node.port.PortObjectSpec) FlowVariablePortObjectSpec(org.knime.core.node.port.flowvariable.FlowVariablePortObjectSpec) ReferencedFile(org.knime.core.internal.ReferencedFile) File(java.io.File) PortObject(org.knime.core.node.port.PortObject) FileStorePortObject(org.knime.core.data.filestore.FileStorePortObject) FlowVariablePortObject(org.knime.core.node.port.flowvariable.FlowVariablePortObject) InactiveBranchPortObject(org.knime.core.node.port.inactive.InactiveBranchPortObject) FlowVariable(org.knime.core.node.workflow.FlowVariable)

Example 2 with NodeExecutionResult

use of org.knime.core.node.workflow.execresult.NodeExecutionResult in project knime-core by knime.

the class SandboxedNodeCreator method copyExistingTablesIntoSandboxContainer.

/**
 * Copies the tables (port and internal) into the context of the corresponding node in the targetWFM. The execution
 * result must fit to the passed node container.
 *
 * @param execResult the object holding the result of the sourceNC. If the sourceNC is a workflow, this must hold
 *            all results of all contained nodes.
 * @param sourceNC the node that produced the execution result.
 * @param targetNC the context into which the tables are copied into
 * @param progressMon For progress information
 * @param copyDataIntoNewContext as per {@link #setCopyData(boolean)}
 * @throws CanceledExecutionException
 * @throws IOException
 */
public static void copyExistingTablesIntoSandboxContainer(final NodeContainerExecutionResult execResult, final NodeContainer sourceNC, final NodeContainer targetNC, final ExecutionMonitor progressMon, final boolean copyDataIntoNewContext) throws CanceledExecutionException, IOException {
    assert targetNC.getNrOutPorts() == sourceNC.getNrOutPorts();
    if (execResult instanceof NativeNodeContainerExecutionResult) {
        NativeNodeContainerExecutionResult sncResult = (NativeNodeContainerExecutionResult) execResult;
        // execResult and node types must match
        assert sourceNC instanceof NativeNodeContainer;
        assert targetNC instanceof NativeNodeContainer;
        // data is to copy ... get the correct execution context
        ExecutionContext targetExec = copyDataIntoNewContext ? ((SingleNodeContainer) targetNC).createExecutionContext() : null;
        NodeExecutionResult ner = sncResult.getNodeExecutionResult();
        // TODO this copy process has to take place in a different place
        // though it needs the final execution context for correct copy
        // of BDT objects
        PortObject[] resultTables = new PortObject[targetNC.getNrOutPorts()];
        int copyCount = resultTables.length;
        // copy also the internally held tables (such as for instance
        // the table in the table view) -- use the copy of the outports
        // if they match (likely they don't)
        PortObject[] oldInternTables = ner.getInternalHeldPortObjects();
        PortObject[] newInternTables = null;
        if (oldInternTables != null) {
            newInternTables = new PortObject[oldInternTables.length];
            copyCount += newInternTables.length;
        }
        // skip flow variable output
        for (int i = 0; i < resultTables.length; i++) {
            ExecutionMonitor sub = progressMon.createSubProgress(1.0 / copyCount);
            progressMon.setMessage("Port " + i);
            PortObject o = ner.getPortObject(i);
            PortObject newPO = copyPortObject(o, sub, targetExec);
            if (newInternTables != null) {
                for (int j = 0; j < oldInternTables.length; j++) {
                    if (oldInternTables[j] == o) {
                        newInternTables[j] = newPO;
                    }
                }
            }
            sub.setProgress(1.0);
            resultTables[i] = newPO;
        }
        if (newInternTables != null) {
            for (int i = 0; i < newInternTables.length; i++) {
                ExecutionMonitor sub = progressMon.createSubProgress(1.0 / copyCount);
                progressMon.setMessage("Internal Table " + i);
                if (newInternTables[i] == null) {
                    PortObject oldT = oldInternTables[i];
                    PortObject newT = copyPortObject(oldT, sub, targetExec);
                    newInternTables[i] = newT;
                }
                sub.setProgress(1.0);
            }
        }
        if (oldInternTables != null) {
            ner.setInternalHeldPortObjects(newInternTables);
        }
        ner.setPortObjects(resultTables);
    } else if (execResult instanceof WorkflowExecutionResult) {
        WorkflowExecutionResult wfmResult = (WorkflowExecutionResult) execResult;
        // exec result and node types must match
        WorkflowManager targetWFM = (WorkflowManager) targetNC;
        WorkflowManager sourceWFM = (WorkflowManager) sourceNC;
        copyIntoSandboxContainerRecursive(sourceWFM, targetWFM, wfmResult, progressMon, copyDataIntoNewContext);
    } else if (execResult instanceof SubnodeContainerExecutionResult) {
        SubnodeContainerExecutionResult subResult = (SubnodeContainerExecutionResult) execResult;
        WorkflowExecutionResult wfmResult = subResult.getWorkflowExecutionResult();
        WorkflowManager targetWFM = ((SubNodeContainer) targetNC).getWorkflowManager();
        WorkflowManager sourceWFM = ((SubNodeContainer) sourceNC).getWorkflowManager();
        copyIntoSandboxContainerRecursive(sourceWFM, targetWFM, wfmResult, progressMon, copyDataIntoNewContext);
    } else {
        throw new IllegalStateException("Unsupported node result type: " + execResult.getClass().getSimpleName());
    }
}
Also used : NodeExecutionResult(org.knime.core.node.workflow.execresult.NodeExecutionResult) WorkflowManager(org.knime.core.node.workflow.WorkflowManager) WorkflowExecutionResult(org.knime.core.node.workflow.execresult.WorkflowExecutionResult) SubNodeContainer(org.knime.core.node.workflow.SubNodeContainer) ExecutionContext(org.knime.core.node.ExecutionContext) NativeNodeContainerExecutionResult(org.knime.core.node.workflow.execresult.NativeNodeContainerExecutionResult) SubnodeContainerExecutionResult(org.knime.core.node.workflow.execresult.SubnodeContainerExecutionResult) ExecutionMonitor(org.knime.core.node.ExecutionMonitor) PortObject(org.knime.core.node.port.PortObject) NativeNodeContainer(org.knime.core.node.workflow.NativeNodeContainer)

Example 3 with NodeExecutionResult

use of org.knime.core.node.workflow.execresult.NodeExecutionResult in project knime-core by knime.

the class Node method createInactiveNodeExecutionResult.

/**
 * @return a {@link NodeExecutionResult} that has all output ports and specs filled with inactive objects, and which
 *         has no internals.
 * @noreference This method is not intended to be referenced by clients.
 */
public NodeExecutionResult createInactiveNodeExecutionResult() {
    NodeExecutionResult result = new NodeExecutionResult();
    PortObject[] pos = new PortObject[getNrOutPorts()];
    Arrays.fill(pos, InactiveBranchPortObject.INSTANCE);
    PortObjectSpec[] poSpecs = new PortObjectSpec[getNrOutPorts()];
    Arrays.fill(poSpecs, InactiveBranchPortObjectSpec.INSTANCE);
    result.setPortObjects(pos);
    result.setPortObjectSpecs(poSpecs);
    return result;
}
Also used : NodeExecutionResult(org.knime.core.node.workflow.execresult.NodeExecutionResult) InactiveBranchPortObjectSpec(org.knime.core.node.port.inactive.InactiveBranchPortObjectSpec) PortObjectSpec(org.knime.core.node.port.PortObjectSpec) FlowVariablePortObjectSpec(org.knime.core.node.port.flowvariable.FlowVariablePortObjectSpec) PortObject(org.knime.core.node.port.PortObject) FileStorePortObject(org.knime.core.data.filestore.FileStorePortObject) FlowVariablePortObject(org.knime.core.node.port.flowvariable.FlowVariablePortObject) InactiveBranchPortObject(org.knime.core.node.port.inactive.InactiveBranchPortObject)

Example 4 with NodeExecutionResult

use of org.knime.core.node.workflow.execresult.NodeExecutionResult in project knime-core by knime.

the class NativeNodeContainer method loadExecutionResult.

/**
 * {@inheritDoc}
 */
@Override
public void loadExecutionResult(final NodeContainerExecutionResult execResult, final ExecutionMonitor exec, final LoadResult loadResult) {
    synchronized (m_nodeMutex) {
        if (InternalNodeContainerState.EXECUTED.equals(getInternalState())) {
            LOGGER.debug(getNameWithID() + " is already executed; won't load execution result");
            return;
        }
        if (!(execResult instanceof NativeNodeContainerExecutionResult)) {
            throw new IllegalArgumentException("Argument must be instance " + "of \"" + NativeNodeContainerExecutionResult.class.getSimpleName() + "\": " + execResult.getClass().getSimpleName());
        }
        super.loadExecutionResult(execResult, exec, loadResult);
        NativeNodeContainerExecutionResult sncExecResult = (NativeNodeContainerExecutionResult) execResult;
        NodeExecutionResult nodeExecResult = sncExecResult.getNodeExecutionResult();
        boolean success = sncExecResult.isSuccess();
        if (success) {
            NodeContext.pushContext(this);
            try {
                m_node.loadExecutionResult(nodeExecResult, new ExecutionMonitor(), loadResult);
                m_node.putOutputTablesIntoGlobalRepository(getParent().getWorkflowDataRepository());
            } finally {
                NodeContext.removeLastContext();
            }
        }
        boolean needsReset = nodeExecResult.needsResetAfterLoad();
        if (!needsReset && success) {
            for (int i = 0; i < getNrOutPorts(); i++) {
                if (m_node.getOutputObject(i) == null) {
                    loadResult.addError("Output object at port " + i + " is null");
                    needsReset = true;
                }
            }
        }
        if (needsReset) {
            execResult.setNeedsResetAfterLoad();
        }
    }
}
Also used : NodeExecutionResult(org.knime.core.node.workflow.execresult.NodeExecutionResult) NativeNodeContainerExecutionResult(org.knime.core.node.workflow.execresult.NativeNodeContainerExecutionResult) ExecutionMonitor(org.knime.core.node.ExecutionMonitor)

Example 5 with NodeExecutionResult

use of org.knime.core.node.workflow.execresult.NodeExecutionResult in project knime-core by knime.

the class StreamingTestNodeExecutionJob method mainExecute.

/**
 * {@inheritDoc}
 */
@Override
protected NodeContainerExecutionStatus mainExecute() {
    NodeContainer nodeContainer = getNodeContainer();
    if (!(nodeContainer instanceof NativeNodeContainer)) {
        String message = "Streaming and distributed TEST execution only available for native nodes (i.e. no meta- or subnodes)";
        nodeContainer.setNodeMessage(new NodeMessage(Type.ERROR, message));
        LOGGER.error(message);
        return NodeContainerExecutionStatus.FAILURE;
    }
    // TODO should actually not be used for execution itself, but is currently!
    NativeNodeContainer localNodeContainer = (NativeNodeContainer) nodeContainer;
    if (localNodeContainer.getNodeModel() instanceof LoopStartNode || localNodeContainer.getNodeModel() instanceof LoopEndNode) {
        String message = "Streaming and distributed TEST execution doesn't work for Loop Start and End nodes.";
        nodeContainer.setNodeMessage(new NodeMessage(Type.ERROR, message));
        LOGGER.error(message);
        return NodeContainerExecutionStatus.FAILURE;
    }
    localNodeContainer.getNodeModel().addWarningListener(w -> {
        if (w != null) {
            m_warningMessages.add(w);
        }
    });
    // get the input object specs
    // includes the flow
    PortObject[] inPortObjects = getPortObjects();
    // variable port object!
    PortObjectSpec[] inPortObjectSpecs = new PortObjectSpec[inPortObjects.length];
    for (int i = 1; i < inPortObjectSpecs.length; i++) {
        // check if it's not an optional in-port
        if (inPortObjects[i] != null) {
            inPortObjectSpecs[i] = inPortObjects[i].getSpec();
        }
    }
    // get input port roles
    LOGGER.info("call local: NodeModel#getInputPortRoles");
    InputPortRole[] inputPortRoles = localNodeContainer.getNodeModel().getInputPortRoles();
    // get flow variables for all non-streamable ports
    // TODO: why only for non-streamable ports?
    // WorkflowManager wfm = localNodeContainer.getParent();
    // ArrayList<FlowObjectStack> flowObjectStacks = new
    // ArrayList<FlowObjectStack>(inPortObjects.length);
    // for (int i = 0; i < inPortObjects.length; i++) {
    // ConnectionContainer con =
    // wfm.getIncomingConnectionFor(localNodeContainer.getID(), i);
    // if ((con != null && i == 0) || (con != null && inputPortRoles[i -
    // 1].isStreamable())) {
    // flowObjectStacks.add(((SingleNodeContainer)wfm.getNodeContainer(con.getSource())).getFlowObjectStack());
    // }
    // }
    // check for distributable ports
    boolean isDistributable = false;
    for (int i = 0; i < inputPortRoles.length; i++) {
        if (inputPortRoles[i].isDistributable()) {
            isDistributable = true;
        }
    }
    /* ---- create node copies and configure ----*/
    // adjust the number of chunks if one of the distributable input table contains less rows than chunks
    int numChunks = isDistributable ? m_numChunks : 1;
    for (int i = 1; i < inPortObjects.length; i++) {
        // without the flow variable port
        if (inputPortRoles[i - 1].isDistributable()) {
            int rowCount = (int) ((BufferedDataTable) inPortObjects[i]).size();
            if (rowCount < numChunks) {
                numChunks = Math.max(1, rowCount);
            }
        }
    }
    // create the 'remote' node containers used for the execution itself
    NativeNodeContainer[] remoteNodeContainers = createNodeCopies(localNodeContainer, numChunks);
    // exactly one execution context per 'remote' node
    ExecutionContext[] remoteExec = createExecutionContexts(remoteNodeContainers);
    // execution context for the original node
    // - mainly for the creation of the input and output tables (to be fed into the 'remote' node copies)
    // - created tables are tracked in m_tableChunksToBeDisposed to be disposed at the end
    // - should actually not be used for the actual execution but is currently! (TODO)
    ExecutionContext localExec = remoteExec[0];
    // configure the node copies
    for (int i = 0; i < remoteNodeContainers.length; i++) {
        try (WorkflowLock lock = localNodeContainer.getParent().lock()) {
            // wfm.createAndSetFlowObjectStackFor(localNodeContainer,
            // flowObjectStacks.toArray(new
            // FlowObjectStack[flowObjectStacks.size()]));
            LOGGER.info("call remote: NodeModel#configure");
            boolean isConfigureOK = remoteNodeContainers[i].callNodeConfigure(inPortObjectSpecs, true);
            if (!isConfigureOK) {
                String message = "Configuration failed";
                nodeContainer.setNodeMessage(new NodeMessage(Type.ERROR, message));
                LOGGER.error(message);
                return NodeContainerExecutionStatus.FAILURE;
            }
        }
    }
    // Otherwise it doesn't make sense.
    if (checkForOverriddenMethod(localNodeContainer, "createInitialStreamableOperatorInternals") && !checkForOverriddenMethod(localNodeContainer, "iterate", StreamableOperatorInternals.class)) {
        m_warningMessages.add("Implementation warning: Overriding the 'createInitialStreamableOperatorInternals'-method without overriding the 'iterate'-method doesn't make sense.");
    }
    // create initial streamable operator internals for the first call of the iterate-method
    LOGGER.info("call local: NodeModel#createInitialStreamableOperatorInternals");
    StreamableOperatorInternals operatorInternals = localNodeContainer.getNodeModel().createInitialStreamableOperatorInternals();
    LOGGER.info("call local: NodeModel#createMergeOperator");
    // can be null
    MergeOperator localMergeOperator = localNodeContainer.getNodeModel().createMergeOperator();
    StreamableOperatorInternals[] newInternals = new StreamableOperatorInternals[numChunks];
    final PortObjectSpec[] inSpecsNoFlowPort = ArrayUtils.remove(inPortObjectSpecs, 0);
    LOGGER.info("call local: NodeModel#iterate");
    // Port types for determining whether a port must be copied or not in createPortInputs(...)
    PortType[] portTypes = new PortType[inPortObjects.length];
    // Skipping the variable port
    for (int i = 1; i < inPortObjects.length; i++) {
        portTypes[i - 1] = localNodeContainer.getInPort(i).getPortType();
    }
    try {
        // create port inputs for the streamable execution
        PortInput[][] portInputs = createPortInputs(inputPortRoles, inPortObjects, portTypes, numChunks, localExec);
        while (localNodeContainer.getNodeModel().iterate(operatorInternals)) {
            newInternals = performIntermediateIteration(remoteNodeContainers, remoteExec, operatorInternals, inSpecsNoFlowPort, portInputs, numChunks, localMergeOperator != null);
            if (localMergeOperator != null) {
                LOGGER.info("call local: MergeOperator#mergeIntermediate");
                operatorInternals = localMergeOperator.mergeIntermediate(newInternals);
            }
            // re-create port inputs since they were already iterated above
            portInputs = createPortInputs(inputPortRoles, inPortObjects, portTypes, numChunks, localExec);
        }
        // create the out specs (after all intermediate iterations have been
        // performed!)
        LOGGER.info("call local: NodeModel#computeFinalOutputSpecs");
        PortObjectSpec[] outSpecsNoFlowPort = null;
        outSpecsNoFlowPort = localNodeContainer.getNodeModel().computeFinalOutputSpecs(operatorInternals, inSpecsNoFlowPort);
        /* ---- take care about the output ---- */
        LOGGER.info("call local: NodeModel#getOutputPortRoles");
        OutputPortRole[] outputPortRoles = localNodeContainer.getNodeModel().getOutputPortRoles();
        // TODO: one single output table (for distributed ports) for all distributed nodes ... should be ok?
        // create the portOutputs for the StreamableOperator#runFinal-method
        // -> if node is run distributed, only distributed ports have to be set (i.e. RowOutputs), otherwise all
        PortOutput[] portOutputs = createPortOutputs(localNodeContainer.getNode(), outputPortRoles, outSpecsNoFlowPort, isDistributable, true, localExec);
        for (int i = 0; i < numChunks; i++) {
            LOGGER.info("call remote: NodeModel#createStreamableOperator");
            StreamableOperator streamableOperator = null;
            streamableOperator = remoteNodeContainers[i].getNodeModel().createStreamableOperator(new PartitionInfo(i, numChunks), inSpecsNoFlowPort);
            // simulates transfer of the internals from the local node to the remote ones
            operatorInternals = saveAndLoadInternals(operatorInternals);
            if (localMergeOperator != null) {
                LOGGER.info("call: StreamableOperator#loadInternals");
                streamableOperator.loadInternals(operatorInternals);
            }
            LOGGER.info("call: StreamableOperator#runFinal");
            try {
                PortOutput[] tmpPortOutputs = portOutputs.clone();
                streamableOperator.runFinal(portInputs[i], portOutputs, remoteExec[i]);
                // make sure that the portOutputs-object hasn't been manipulated directly (only it's containing objects)
                if (IntStream.range(0, portOutputs.length).anyMatch(j -> {
                    return tmpPortOutputs[j] != portOutputs[j];
                })) {
                    throw new IllegalStateException("Output array must not be manipulated.");
                }
            } catch (ClassCastException e) {
                throw new ClassCastException(e.getMessage() + ". Likely reason: port-role is not set as streamable -> overwrite get[Input|Ouptut]PortRoles()-methods in NodeModel.");
            }
            checkClosedPortOutputs(portOutputs);
            if (localMergeOperator != null) {
                LOGGER.info("call: StreamableOperator#saveInternals");
                newInternals[i] = saveAndLoadInternals(streamableOperator.saveInternals());
            }
        }
        if (localMergeOperator != null) {
            LOGGER.info("call: MergeOperator#mergeFinals");
            operatorInternals = localMergeOperator.mergeFinal(newInternals);
        } else if (numChunks == 1) {
            operatorInternals = newInternals[0];
        }
        if (localMergeOperator != null) {
            LOGGER.info("call local: NodeModel#finishStreamableExecution");
            // create the port outputs for the NodeModel#finishStreamableExecution-method -> only non-distributed ports have to be provided here
            PortOutput[] nonDistrPortOutputs;
            if (isDistributable) {
                nonDistrPortOutputs = createPortOutputs(localNodeContainer.getNode(), outputPortRoles, outSpecsNoFlowPort, isDistributable, false, localExec);
            } else {
                // if the node is not distributable we assume that all port-outputs have already been set in the runFinal-Method
                // and don't pass any port outputs here -> the finishStreamableExecution method is than only be used
                // to set warning messages etc.
                nonDistrPortOutputs = new PortOutput[outputPortRoles.length];
            }
            PortOutput[] tmpPortOutputs = nonDistrPortOutputs.clone();
            localNodeContainer.getNodeModel().finishStreamableExecution(operatorInternals, localExec, nonDistrPortOutputs);
            // make sure that the pArrays.equals(a, a2)ortOutputs-object hasn't been manipulated directly, only it's containing objects
            if (IntStream.range(0, portOutputs.length).anyMatch(j -> {
                return tmpPortOutputs[j] != nonDistrPortOutputs[j];
            })) {
                throw new IllegalStateException("Output array must not be manipulated.");
            }
            // merge the portOutputs and the nonDistrPortOutputs
            for (int i = 0; i < nonDistrPortOutputs.length; i++) {
                if (nonDistrPortOutputs[i] != null) {
                    portOutputs[i] = nonDistrPortOutputs[i];
                }
            }
        } else {
            // check whether the current node model overrides the #finishStreamableExecution-method
            if (checkForOverriddenMethod(localNodeContainer, "finishStreamableExecution", StreamableOperatorInternals.class, ExecutionContext.class, PortOutput[].class)) {
                // method has been overridden -> createMergeOperator-method actually needs to be implemented as well!
                throw new IllegalStateException("The 'NodeModel#finishStreamExecution'-method is overridden but no merge operator provided. Please override the 'NodeModel#createMergeOperator'-method as well.");
            }
        }
        PortObject[] outPortObjects = new PortObject[localNodeContainer.getNrOutPorts()];
        PortObjectSpec[] outPortObjectSpecs = new PortObjectSpec[localNodeContainer.getNrOutPorts()];
        // set variable out port
        outPortObjects[0] = FlowVariablePortObject.INSTANCE;
        // set variable out port
        outPortObjectSpecs[0] = FlowVariablePortObjectSpec.INSTANCE;
        for (int i = 1; i < outPortObjects.length; i++) {
            // retrieve the out port objects
            if (portOutputs[i - 1] instanceof BufferedDataContainerRowOutput) {
                BufferedDataTable table = ((BufferedDataContainerRowOutput) portOutputs[i - 1]).getDataTable();
                outPortObjects[i] = table;
                // check if table is empty and set appropriate warning message
                if (table.size() == 0) {
                    m_warningMessages.add("Node created an empty data table.");
                }
            } else {
                outPortObjects[i] = ((PortObjectOutput) portOutputs[i - 1]).getPortObject();
            }
            // retrieve the out port object specs
            if (outSpecsNoFlowPort != null && outSpecsNoFlowPort[i - 1] != null) {
                // get out port specs as return by the configure-method (happen to be null in some cases, i.e. the Transpose-node)
                outPortObjectSpecs[i] = outSpecsNoFlowPort[i - 1];
            } else if (outPortObjects[i] != null) {
                // port objects can be null (mainly in loop iterations)
                // get outport specs as given by the result port objects
                outPortObjectSpecs[i] = outPortObjects[i].getSpec();
            }
        }
        NativeNodeContainerExecutionResult execResult = localNodeContainer.createExecutionResult(localExec);
        NodeExecutionResult nodeExecResult = execResult.getNodeExecutionResult();
        nodeExecResult.setInternalHeldPortObjects(null);
        nodeExecResult.setNodeInternDir(null);
        nodeExecResult.setPortObjects(outPortObjects);
        nodeExecResult.setPortObjectSpecs(outPortObjectSpecs);
        WorkflowPersistor.LoadResult loadResult = new WorkflowPersistor.LoadResult("streaming test exec result");
        execResult.setSuccess(true);
        // TODO: since some port objects are null if in an iteration of a loop end node, the execution result cannot be loaded every time
        // possible workaround: check for all port objects to be non-null and only load execution result if that's the case
        // if (Arrays.stream(outPortObjects).noneMatch(p -> p == null)) {
        localNodeContainer.loadExecutionResult(execResult, localExec, loadResult);
        // }
        if (!m_warningMessages.isEmpty()) {
            String joinedMessages = m_warningMessages.stream().collect(Collectors.joining("\n"));
            NodeMessage nm = new NodeMessage(Type.WARNING, joinedMessages);
            localNodeContainer.setNodeMessage(nm);
            execResult.setMessage(nm);
        }
        return execResult;
    } catch (Exception e) {
        // copied from Node.java
        boolean isCanceled = e instanceof CanceledExecutionException;
        isCanceled = isCanceled || e instanceof InterruptedException;
        // TODO this can all be shortened to exec.isCanceled()?
        // isCanceled = isCanceled || localExec.isCanceled(); //not visible
        // writing to a buffer is done asynchronously -- if this thread
        // is interrupted while waiting for the IO thread to flush we take
        // it as a graceful exit
        isCanceled = isCanceled || (e instanceof DataContainerException && e.getCause() instanceof InterruptedException);
        if (isCanceled) {
            localNodeContainer.setNodeMessage(NodeMessage.newWarning("Execution canceled"));
            return NodeContainerExecutionStatus.FAILURE;
        }
        localNodeContainer.getNode().createErrorMessageAndNotify("Execute failed: " + e.getMessage(), e);
        return NodeContainerExecutionStatus.FAILURE;
    } finally {
        // remove virtual nodes from workflow
        removeNodeCopies(remoteNodeContainers);
        // other things to be done in post execution
        postExecution(remoteExec, remoteNodeContainers);
        // clear/dispose all newly created table chunks if there are any (created via creatTableChunks)
        m_tableChunksToBeDisposed.forEach(c -> c.dispose());
        m_tableChunksToBeDisposed.clear();
    }
}
Also used : StreamableOperator(org.knime.core.node.streamable.StreamableOperator) WorkflowPersistor(org.knime.core.node.workflow.WorkflowPersistor) NodeContainer(org.knime.core.node.workflow.NodeContainer) NativeNodeContainer(org.knime.core.node.workflow.NativeNodeContainer) StreamableOperatorInternals(org.knime.core.node.streamable.StreamableOperatorInternals) LoopEndNode(org.knime.core.node.workflow.LoopEndNode) CanceledExecutionException(org.knime.core.node.CanceledExecutionException) PortObjectSpec(org.knime.core.node.port.PortObjectSpec) FlowVariablePortObjectSpec(org.knime.core.node.port.flowvariable.FlowVariablePortObjectSpec) BufferedDataTable(org.knime.core.node.BufferedDataTable) NativeNodeContainerExecutionResult(org.knime.core.node.workflow.execresult.NativeNodeContainerExecutionResult) PartitionInfo(org.knime.core.node.streamable.PartitionInfo) LoopStartNode(org.knime.core.node.workflow.LoopStartNode) PortObject(org.knime.core.node.port.PortObject) FlowVariablePortObject(org.knime.core.node.port.flowvariable.FlowVariablePortObject) WorkflowLock(org.knime.core.node.workflow.WorkflowLock) NodeExecutionResult(org.knime.core.node.workflow.execresult.NodeExecutionResult) DataContainerException(org.knime.core.data.container.DataContainerException) PortOutput(org.knime.core.node.streamable.PortOutput) CanceledExecutionException(org.knime.core.node.CanceledExecutionException) IOException(java.io.IOException) DataContainerException(org.knime.core.data.container.DataContainerException) OutputPortRole(org.knime.core.node.streamable.OutputPortRole) ExecutionContext(org.knime.core.node.ExecutionContext) InputPortRole(org.knime.core.node.streamable.InputPortRole) NodeMessage(org.knime.core.node.workflow.NodeMessage) MergeOperator(org.knime.core.node.streamable.MergeOperator) NativeNodeContainer(org.knime.core.node.workflow.NativeNodeContainer) PortType(org.knime.core.node.port.PortType)

Aggregations

NodeExecutionResult (org.knime.core.node.workflow.execresult.NodeExecutionResult)4 PortObject (org.knime.core.node.port.PortObject)3 NativeNodeContainerExecutionResult (org.knime.core.node.workflow.execresult.NativeNodeContainerExecutionResult)3 IOException (java.io.IOException)2 DataContainerException (org.knime.core.data.container.DataContainerException)2 FileStorePortObject (org.knime.core.data.filestore.FileStorePortObject)2 ExecutionContext (org.knime.core.node.ExecutionContext)2 ExecutionMonitor (org.knime.core.node.ExecutionMonitor)2 PortObjectSpec (org.knime.core.node.port.PortObjectSpec)2 FlowVariablePortObject (org.knime.core.node.port.flowvariable.FlowVariablePortObject)2 FlowVariablePortObjectSpec (org.knime.core.node.port.flowvariable.FlowVariablePortObjectSpec)2 NativeNodeContainer (org.knime.core.node.workflow.NativeNodeContainer)2 Rectangle (java.awt.Rectangle)1 BufferedInputStream (java.io.BufferedInputStream)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 File (java.io.File)1 FileInputStream (java.io.FileInputStream)1 InputStream (java.io.InputStream)1 PrintWriter (java.io.PrintWriter)1