public DocumentNodeState getNodeAtRevision()

in oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java [945:1051]


    public DocumentNodeState getNodeAtRevision(@NotNull DocumentNodeStore nodeStore,
                                               @NotNull RevisionVector readRevision,
                                               @Nullable Revision lastModified) {
        Map<Revision, String> validRevisions = Maps.newHashMap();
        Branch branch = nodeStore.getBranches().getBranch(readRevision);
        LastRevs lastRevs = createLastRevs(readRevision,
                nodeStore, branch, lastModified);

        Revision min = getLiveRevision(nodeStore, readRevision, validRevisions, lastRevs);
        if (min == null) {
            // deleted
            return null;
        }
        Path path = getPath();
        List<PropertyState> props = Lists.newArrayList();
        for (String key : keySet()) {
            if (!Utils.isPropertyName(key)) {
                continue;
            }
            // ignore when local map is empty (OAK-2442)
            SortedMap<Revision, String> local = getLocalMap(key);
            if (local.isEmpty()) {
                continue;
            }
            // first check local map, which contains most recent values
            Value value = getLatestValue(nodeStore, local.entrySet(),
                    readRevision, validRevisions, lastRevs);

            // check if there may be more recent values in a previous document
            if (value != null
                    && !getPreviousRanges().isEmpty()
                    && !isMostRecentCommitted(local, value.revision, nodeStore)) {
                // not reading the most recent value, we may need to
                // consider previous documents as well
                for (Revision prev : getPreviousRanges().keySet()) {
                    if (prev.compareRevisionTimeThenClusterId(value.revision) > 0) {
                        // a previous document has more recent changes
                        // than value.revision
                        value = null;
                        break;
                    }
                }
            }

            if (value == null && !getPreviousRanges().isEmpty()) {
                // check revision history
                value = getLatestValue(nodeStore, getVisibleChanges(key, readRevision),
                        readRevision, validRevisions, lastRevs);
            }
            String propertyName = Utils.unescapePropertyName(key);
            String v = value != null ? value.value : null;
            if (v != null){
                props.add(nodeStore.createPropertyState(propertyName, v));
            }
        }

        // when was this node last modified?
        RevisionVector lastRevision = new RevisionVector(min);
        RevisionVector branchBase = null;
        if (branch != null) {
            branchBase = branch.getBase(readRevision.getBranchRevision());
        }
        for (Revision r : lastRevs) {
            if (readRevision.isRevisionNewer(r)) {
                // the node has a _lastRev which is newer than readRevision
                // this means we don't know when this node was
                // modified by an operation on a descendant node between
                // current lastRevision and readRevision. therefore we have
                // to stay on the safe side and use readRevision
                Revision rev = readRevision.getRevision(r.getClusterId());
                if (rev != null) {
                    lastRevision = lastRevision.update(rev);
                } else {
                    // readRevision does not have a revision for this
                    // clusterId -> remove from lastRevision
                    lastRevision = lastRevision.remove(r.getClusterId());
                }
            } else if (branchBase != null && branchBase.isRevisionNewer(r)) {
                // readRevision is on a branch and the node has a
                // _lastRev which is newer than the base of the branch
                // we cannot use this _lastRev because it is not visible
                // from this branch. highest possible revision of visible
                // changes is the base of the branch
                Revision rev = branchBase.getRevision(r.getClusterId());
                if (rev != null) {
                    lastRevision = lastRevision.update(rev);
                } else {
                    // branchBase does not have a revision for this
                    // clusterId -> remove from lastRevision
                    lastRevision = lastRevision.remove(r.getClusterId());
                }
            } else if (lastRevision.isRevisionNewer(r)) {
                lastRevision = lastRevision.update(r);
            }
        }
        if (branch != null) {
            // read from a branch
            // -> possibly overlay with unsaved last revs from branch
            lastRevs.updateBranch(branch.getUnsavedLastRevision(path, readRevision.getBranchRevision()));
            Revision r = lastRevs.getBranchRevision();
            if (r != null) {
                lastRevision = lastRevision.update(r);
            }
        }

        return new DocumentNodeState(nodeStore, path, readRevision, props, hasChildren(), lastRevision);
    }