All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.mdsal.dom.spi.query.DOMQueryMatcher Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.mdsal.dom.spi.query;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Optional;
import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate;
import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.Match;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;

/**
 * Generalized utility for matching predicates. Split out of {@link DOMQueryIterator} for simplicity.
 */
final class DOMQueryMatcher {
    private DOMQueryMatcher() {
        // Utility class
    }

    static boolean matchesAll(final NormalizedNode data, final List predicates) {
        // TODO: it would be nice if predicates were somehow structured -- can we perhaps sort them by their
        //       InstanceIdentifier? If the predicates are sharing a common subpath. Hence if we can guarantee
        //       predicates are in a certain order, we would not end up in subsequent re-lookups of the same node.
        Deque pathArgs = null;
        for (DOMQueryPredicate pred : predicates) {
            // So now, dealing with implementations: YangInstanceIdentifier.getLastPathArgument() is always cheap.
            // If its parent is YangInstanceIdentifier.ROOT (i.e. isEmpty() == true), we are dealing with a last-step
            // lookup -- in which case we forgo iteration:
            final YangInstanceIdentifier path = pred.relativePath();
            if (path.coerceParent().isEmpty()) {
                if (!matchesChild(pred.match(), data, path.getLastPathArgument())) {
                    return false;
                }
                continue;
            }

            // We are leaking path arguments in a bid for object reuse: we end up reusing same object as needed
            if (pathArgs == null) {
                pathArgs = new ArrayDeque<>();
            }
            pathArgs.addAll(path.getPathArguments());

            // The stage is set, we now have to deal with potential negation.
            if (!matchesAny(pred.match(), data, pathArgs)) {
                return false;
            }

            pathArgs.clear();
        }
        return true;
    }

    private static boolean matchesAny(final Match match, final NormalizedNode data,
            final Deque pathArgs) {
        // Guaranteed to have at least one item
        final PathArgument pathArg = pathArgs.pop();
        // Ultimate item -- reuse lookup & match
        if (pathArgs.isEmpty()) {
            pathArgs.push(pathArg);
            return matchesChild(match, data, pathArg);
        }

        final Optional direct = NormalizedNodes.getDirectChild(data, pathArg);
        if (direct.isPresent()) {
            final boolean ret = matchesAny(match, direct.orElseThrow(), pathArgs);
            pathArgs.push(pathArg);
            return ret;
        }

        // We may be dealing with a wildcard here. NodeIdentifier is a final class, hence this is as fast as it gets.
        if (pathArg instanceof NodeIdentifier && data instanceof MapNode map) {
            for (MapEntryNode child : map.body()) {
                if (matchesAny(match, child, pathArgs)) {
                    pathArgs.push(pathArg);
                    return true;
                }
            }
        }

        pathArgs.push(pathArg);
        return false;
    }

    private static boolean matchesChild(final Match match, final NormalizedNode data, final PathArgument pathArg) {
        // Try the direct approach...
        final Optional direct = NormalizedNodes.getDirectChild(data, pathArg);
        if (direct.isPresent()) {
            return match.test(direct.orElseThrow());
        }

        // We may be dealing with a wildcard here. NodeIdentifier is a final class, hence this is as fast as it gets.
        if (pathArg instanceof NodeIdentifier && data instanceof MapNode map) {
            for (MapEntryNode child : map.body()) {
                if (match.test(child)) {
                    return true;
                }
            }
        }

        return match.test(null);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy