private StackElement addNode()

in vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewImporter.java [845:966]


    private StackElement addNode(DocViewNode2 docViewNode) throws RepositoryException, IOException {
        final Node currentNode = stack.getNode();

        Collection<DocViewProperty2> preprocessedProperties = new LinkedList<>(docViewNode.getProperties());
        Node existingNode = null;
        if (NameConstants.ROOT.equals(docViewNode.getName())) {
            // special case for root node update
            existingNode = currentNode;
        } else {
            if (stack.checkForNode() && currentNode.hasNode(docViewNode.getName().toString())) {
                existingNode = currentNode.getNode(docViewNode.getName().toString());
            }
            Optional<String> identifier = docViewNode.getIdentifier();
            if (identifier.isPresent()) {
                try {
                    // does uuid already exist in the repo?
                    Node sameIdNode = session.getNodeByIdentifier(identifier.get());
                    String newNodePath = currentNode.getPath() + "/" + npResolver.getJCRName(docViewNode.getName());
                    // edge-case: same node path -> uuid is kept
                    if (existingNode != null && existingNode.getPath().equals(sameIdNode.getPath())) {
                        log.debug("Node at {} with existing identifier {} is being updated without modifying its identifier", existingNode.getPath(), docViewNode.getIdentifier());
                    } else {
                        log.warn("Node Collision: To-be imported node {} uses a node identifier {} which is already taken by {}, trying to resolve conflict according to policy {}", 
                                newNodePath, docViewNode.getIdentifier(), sameIdNode.getPath(), idConflictPolicy.name());
                        if (idConflictPolicy == IdConflictPolicy.FAIL) {
                            // uuid found in path covered by filter
                            if (isIncluded(sameIdNode, 0)) {
                                Info sameIdNodeInfo = importInfo.getInfo(sameIdNode.getPath());
                                // is the conflicting node part of the package (i.e. the package contained duplicate uuids)
                                if (sameIdNodeInfo != null && sameIdNodeInfo.getType() != Type.DEL) {
                                    throw new ReferentialIntegrityException("Node identifier " + docViewNode.getIdentifier() + " already taken by node " + sameIdNode.getPath() + " from the same package");
                                } else {
                                    log.warn("Trying to remove existing conflicting node {} (and all its references)", sameIdNode.getPath());
                                    removeReferences(sameIdNode);
                                    String sameIdNodePath = sameIdNode.getPath();
                                    session.removeItem(sameIdNodePath);
                                    log.warn("Node {} and its references removed", sameIdNodePath);
                                }
                                existingNode = null;
                            } else {
                                // uuid found in path not-covered by filter
                                throw new ReferentialIntegrityException("Node identifier " + docViewNode.getIdentifier() + " already taken by node " + sameIdNode.getPath());
                            }
                        } else if (idConflictPolicy == IdConflictPolicy.LEGACY) {
                            // is the conflicting node a sibling
                            if (sameIdNode.getParent().isSame(currentNode)) {
                                String sameIdNodePath = sameIdNode.getPath();
                                if (isIncluded(sameIdNode, 0)) {
                                    log.warn("Existing conflicting node {} has same parent as to-be imported one and is contained in the filter, trying to remove it.", sameIdNodePath);
                                    session.removeItem(sameIdNodePath); // references point to new node afterwards
                                    importInfo.onDeleted(sameIdNodePath);
                                } else {
                                    log.warn("Existing conflicting node {} has same parent as to-be imported one and is not contained in the filter, ignoring new node but continue with children below existing conflicting node", sameIdNodePath);
                                    importInfo.onRemapped(newNodePath, sameIdNodePath);
                                    existingNode = sameIdNode;
                                }
                            } else {
                                log.warn("To-be imported node and existing conflicting node have different parents. Will create new identifier for the former. ({})",
                                        newNodePath);
                                preprocessedProperties.removeIf(p -> p.getName().equals(NameConstants.JCR_UUID) 
                                        || p.getName().equals(NameConstants.JCR_BASEVERSION) 
                                        || p.getName().equals(NameConstants.JCR_PREDECESSORS)
                                        || p.getName().equals(NameConstants.JCR_SUCCESSORS)
                                        || p.getName().equals(NameConstants.JCR_VERSIONHISTORY));
                            }
                        }
                    }
                } catch (ItemNotFoundException e) {
                    // ignore
                }
            }
        }

        // check if new node needs to be checked in
        preprocessedProperties.removeIf(p -> p.getName().equals(NameConstants.JCR_ISCHECKEDOUT));
        boolean isCheckedIn = "false".equals(docViewNode.getPropertyValue(NameConstants.JCR_ISCHECKEDOUT).orElse("true"));

        // create or update node
        boolean isNew = existingNode == null;
        if (isNew) {
            // workaround for bug in jcr2spi if mixins are empty
            if (!docViewNode.hasProperty(NameConstants.JCR_MIXINTYPES)) {
                preprocessedProperties.add(new DocViewProperty2(NameConstants.JCR_MIXINTYPES, Collections.emptyList(), PropertyType.NAME));
            }

            stack.ensureCheckedOut();
            existingNode = createNewNode(currentNode, docViewNode.cloneWithDifferentProperties(preprocessedProperties));
            if (existingNode.getDefinition() == null) {
                throw new RepositoryException("Child node not allowed.");
            }
            if (existingNode.isNodeType(JcrConstants.NT_RESOURCE)) {
                if (!existingNode.hasProperty(JcrConstants.JCR_DATA)) {
                    importInfo.onMissing(existingNode.getPath() + "/" + JcrConstants.JCR_DATA);
                }
            } else if (isCheckedIn) {
                // don't rely on isVersionable here, since SPI might not have this info yet
                importInfo.registerToVersion(existingNode.getPath());
            }
            importInfo.onCreated(existingNode.getPath());

        } else if (isIncluded(existingNode, existingNode.getDepth() - rootDepth)) {
            if (isCheckedIn) {
                // don't rely on isVersionable here, since SPI might not have this info yet
                importInfo.registerToVersion(existingNode.getPath());
            }
            ImportMode importMode = wspFilter.getImportMode(existingNode.getPath());
            Node updatedNode = updateExistingNode(existingNode, docViewNode.cloneWithDifferentProperties(preprocessedProperties), importMode);
            if (updatedNode != null) {
                if (updatedNode.isNodeType(JcrConstants.NT_RESOURCE) && !updatedNode.hasProperty(JcrConstants.JCR_DATA)) {
                    importInfo.onMissing(existingNode.getPath() + "/" + JcrConstants.JCR_DATA);
                }
                importInfo.onModified(updatedNode.getPath());
                existingNode = updatedNode;
            } else {
                importInfo.onNop(existingNode.getPath());
            }
        } else {
            // remove registered binaries outside of the filter (JCR-126)
            binaries.remove(existingNode.getPath());
        }
        return new StackElement(existingNode, isNew);
    }