use of org.knime.core.node.workflow.capture.WorkflowSegment in project knime-core by knime.
the class WorkflowCaptureOperation method capture.
/**
* Carries out the actual capture-operation and returns the captured sub-workflow as a {@link WorkflowSegment}.
*
* @return the captured sub-workflow
*/
public WorkflowSegment capture() {
WorkflowManager tempParent = null;
try (WorkflowLock lock = m_wfm.lock()) {
NodeID endNodeID = m_endNode.getID();
WorkflowCreationHelper workflowCreationHelper = new WorkflowCreationHelper();
Optional.ofNullable(NodeContext.getContext()).map(NodeContext::getWorkflowManager).map(WorkflowManager::getContext).ifPresent(workflowCreationHelper::setWorkflowContext);
tempParent = WorkflowManager.EXTRACTED_WORKFLOW_ROOT.createAndAddProject("Capture-" + endNodeID, workflowCreationHelper);
// "scope body" -- will copy those nodes later
List<NodeContainer> nodesInScope = m_wfm.getWorkflow().getNodesInScope(m_endNode);
// "scope body" and port object ref readers -- will determine bounding box and move them to the top left
List<NodeContainer> nodesToDetermineBoundingBox = new ArrayList<>(nodesInScope);
// copy nodes in scope body
WorkflowCopyContent.Builder copyContent = WorkflowCopyContent.builder();
NodeID[] allIDs = nodesInScope.stream().map(NodeContainer::getID).toArray(NodeID[]::new);
HashSet<NodeID> allIDsHashed = new HashSet<>(Arrays.asList(allIDs));
// port object reader nodes grouped by the original node
Map<NodeID, List<NodeID>> portObjectReaderGroups = new HashMap<>();
Set<NodeIDSuffix> addedPortObjectReaderNodes = new HashSet<>();
NodeID[] allButScopeIDs = ArrayUtils.removeElements(allIDs, endNodeID, m_startNode.getID());
copyContent.setNodeIDs(allButScopeIDs);
copyContent.setIncludeInOutConnections(false);
final int[] boundingBox = NodeUIInformation.getBoundingBoxOf(nodesToDetermineBoundingBox);
final int[] moveUIDist = new int[] { -boundingBox[0] + 50, -boundingBox[1] + 50 };
copyContent.setPositionOffset(moveUIDist);
tempParent.copyFromAndPasteHere(m_wfm, copyContent.build());
// collect nodes outside the scope body but connected to the scope body (only incoming)
// maps to 'pasted' node id
Map<Pair<NodeID, Integer>, NodeID> visitedSrcPorts = new HashMap<>();
FlowVirtualScopeContext virtualScopeContext = getVirtualScopeContext(m_startNode);
for (int i = 0; i < allButScopeIDs.length; i++) {
NodeContainer oldNode = m_wfm.getNodeContainer(allButScopeIDs[i]);
for (int p = 0; p < oldNode.getNrInPorts(); p++) {
ConnectionContainer c = m_wfm.getIncomingConnectionFor(allButScopeIDs[i], p);
if (c == null) {
// ignore: no incoming connection
} else if (allIDsHashed.contains(c.getSource())) {
// ignore: connection already retained by paste persistor
} else {
Pair<NodeID, Integer> currentSrcPort = Pair.create(c.getSource(), c.getSourcePort());
if (!visitedSrcPorts.containsKey(currentSrcPort)) {
// only add portObjectReader if not inserted already in previous loop iteration
// add port object reader
NodeID pastedID = addPortObjectReferenceReader(m_wfm, tempParent, c, virtualScopeContext);
NodeIDSuffix pastedIDSuffix = NodeIDSuffix.create(tempParent.getID(), pastedID);
// position
NodeID sourceID = c.getSource();
NodeUIInformation sourceUIInformation = getSourceNodeAndUIInformation(sourceID, c.getDest(), nodesToDetermineBoundingBox);
tempParent.getNodeContainer(pastedID).setUIInformation(sourceUIInformation);
// keeping track
visitedSrcPorts.put(Pair.create(c.getSource(), c.getSourcePort()), pastedID);
addedPortObjectReaderNodes.add(pastedIDSuffix);
portObjectReaderGroups.computeIfAbsent(currentSrcPort.getFirst(), id -> new ArrayList<>()).add(pastedID);
}
// connect all new port object readers to the in-scope-nodes
NodeIDSuffix destID = NodeIDSuffix.create(m_wfm.getID(), c.getDest());
tempParent.addConnection(visitedSrcPorts.get(currentSrcPort), 1, destID.prependParent(tempParent.getID()), c.getDestPort());
}
}
}
groupAndPositionPortObjectReaders(tempParent, portObjectReaderGroups, addedPortObjectReaderNodes, moveUIDist);
// transfer editor settings, too
tempParent.setEditorUIInformation(m_wfm.getEditorUIInformation());
List<Input> workflowFragmentInputs = getInputs();
List<Output> workflowFragmentOutputs = getOutputs();
return new WorkflowSegment(tempParent, workflowFragmentInputs, workflowFragmentOutputs, addedPortObjectReaderNodes);
} catch (Exception e) {
if (tempParent != null) {
WorkflowManager.EXTRACTED_WORKFLOW_ROOT.removeNode(tempParent.getID());
tempParent = null;
}
throw e;
}
}
use of org.knime.core.node.workflow.capture.WorkflowSegment in project knime-core by knime.
the class WorkflowCaptureOperation method getInputs.
/**
* Returns the input of the (to be) captured sub-workflow, i.e. the same ports {@link #capture()} with a
* subsequent {@link WorkflowSegment#getConnectedInputs()} would return.
*
* @return the inputs of the (to be) captured workflow fragment
*/
public List<Input> getInputs() {
List<Input> res = new ArrayList<>();
for (int i = 0; i < m_startNode.getNrOutPorts(); i++) {
Set<PortID> connections = m_wfm.getOutgoingConnectionsFor(m_startNode.getID(), i).stream().map(cc -> {
return new PortID(NodeIDSuffix.create(m_wfm.getID(), cc.getDest()), cc.getDestPort());
}).collect(Collectors.toSet());
NodeOutPort outPort = m_startNode.getOutPort(i);
res.add(new Input(outPort.getPortType(), castToDTSpecOrNull(outPort.getPortObjectSpec()), connections));
}
return res;
}
Aggregations