private boolean doExcludes()

in oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/filter/ChangeSetFilterImpl.java [201:329]


    private boolean doExcludes(ChangeSet changeSet) {
        if (changeSet.anyOverflow()) {
            // in case of an overflow we could
            // either try to still determine include/exclude based on non-overflown
            // sets - or we can do a fail-stop and determine this as too complex
            // to try-to-exclude, and just include
            //TODO: optimize this later
            return false;
        }
        if (changeSet.doesHitMaxPathDepth()) {
            // then we might or might not include this - but without
            // further complicated checks this can't be determined for sure
            // so for simplicity reason just check first level include names
            // if available
            if (firstLevelIncludeNames == null) {
                return false;
            }
            for (String parentPath : changeSet.getParentPaths()) {
                String firstLevelName = firstLevelName(parentPath);
                if (firstLevelName != null && firstLevelIncludeNames.contains(firstLevelName)) {
                    return false;
                }
            }
            // none of the first level include names matched any parentPath
            // we can safely exclude this change set
            return true;
        }
        final Set<String> parentPaths = new HashSet<String>(changeSet.getParentPaths());

        // first go through the unprecise excludes. if that has any hit,
        // we have to let it pass as include
        boolean unpreciseExclude = false;
        if (this.unpreciseExcludePathPatterns.size() != 0) {
            final Iterator<String> it = parentPaths.iterator();
            while (it.hasNext()) {
                final String aParentPath = it.next();
                if (patternsMatch(this.unpreciseExcludePathPatterns, aParentPath)) {
                    // if there is an unprecise match we keep track of that fact
                    // for later in this method
                    unpreciseExclude = true;
                    break;
                }
            }
        }
        
        // first go through excludes to remove those that are explicitly
        // excluded
        if (this.excludePathPatterns.size() != 0) {
            final Iterator<String> it = parentPaths.iterator();
            while (it.hasNext()) {
                final String aParentPath = it.next();
                if (patternsMatch(this.excludePathPatterns, aParentPath)) {
                    // if an exclude pattern matches, remove the parentPath
                    it.remove();
                }
            }
        }
        // note that cut-off paths are not applied with excludes,
        // eg if excludePaths contains /var/foo/bar and path contains /var/foo
        // with a maxPathLevel of 2, that might very well mean that
        // the actual path would have been /var/foo/bar, but we don't know.
        // so we cannot exclude it here and thus have a potential false negative
        // (ie we didn't exclude it in the prefilter)

        // now remainingPaths contains what is not excluded,
        // then check if it is included
        boolean included = false;
        for (String aPath : parentPaths) {
            // direct set contains is fastest, lets try that first
            if (this.rootIncludePaths.contains(aPath)) {
                included = true;
                break;
            }
            if (firstLevelIncludeNames != null) {
                final String firstLevelName = firstLevelName(aPath);
                if (firstLevelName != null && !firstLevelIncludeNames.contains(firstLevelName)) {
                    // then the 'first level name check' concluded that
                    // it's not in any include path - hence we can skip
                    // the (more expensive) pattern check
                    continue;
                }
            }
            if (patternsMatch(this.includePathPatterns, aPath)) {
                included = true;
                break;
            }
        }

        if (!included) {
            // well then we can definitely say that this commit is excluded
            return true;
        } else if (unpreciseExclude) {
            // then it might have been excluded but we are not sure
            // in which case we return false (as that's safe always)
            return false;
        }

        if (this.propertyNames != null && this.propertyNames.size() != 0) {
            if (disjoint(changeSet.getPropertyNames(), this.propertyNames)) {
                // if propertyNames are defined then if we can't find any
                // at this stage (if !included) then this equals to filtering out
                return true;
            }
            // otherwise we have found a match, but one of the
            // nodeType/nodeNames
            // could still filter out, so we have to continue...
        }

        if (this.parentNodeTypes != null && this.parentNodeTypes.size() != 0) {
            if (disjoint(changeSet.getParentNodeTypes(), this.parentNodeTypes)) {
                // same story here: if nodeTypes is defined and we can't find any
                // match
                // then we're done now
                return true;
            }
            // otherwise, again, continue
        }

        if (this.parentNodeNames != null && this.parentNodeNames.size() != 0) {
            // and a 3rd time, if we can't find any nodeName match
            // here, then we're filtering out
            if (disjoint(changeSet.getParentNodeNames(), this.parentNodeNames)) {
                return true;
            }
        }

        // at this stage we haven't found any exclude, so we're likely including
        return false;
    }