2 * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.dom.spi.query;
10 import java.util.ArrayDeque;
11 import java.util.Deque;
12 import java.util.List;
13 import java.util.Optional;
14 import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate;
15 import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.Match;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
19 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
25 * Generalized utility for matching predicates. Split out of {@link DOMQueryIterator} for simplicity.
27 final class DOMQueryMatcher {
28 private DOMQueryMatcher() {
32 static boolean matchesAll(final NormalizedNode data, final List<? extends DOMQueryPredicate> predicates) {
33 // TODO: it would be nice if predicates were somehow structured -- can we perhaps sort them by their
34 // InstanceIdentifier? If the predicates are sharing a common subpath. Hence if we can guarantee
35 // predicates are in a certain order, we would not end up in subsequent re-lookups of the same node.
36 Deque<PathArgument> pathArgs = null;
37 for (DOMQueryPredicate pred : predicates) {
38 // So now, dealing with implementations: YangInstanceIdentifier.getLastPathArgument() is always cheap.
39 // If its parent is YangInstanceIdentifier.ROOT (i.e. isEmpty() == true), we are dealing with a last-step
40 // lookup -- in which case we forgo iteration:
41 final YangInstanceIdentifier path = pred.relativePath();
42 if (path.coerceParent().isEmpty()) {
43 if (!matchesChild(pred.match(), data, path.getLastPathArgument())) {
49 // We are leaking path arguments in a bid for object reuse: we end up reusing same object as needed
50 if (pathArgs == null) {
51 pathArgs = new ArrayDeque<>();
53 pathArgs.addAll(path.getPathArguments());
55 // The stage is set, we now have to deal with potential negation.
56 if (!matchesAny(pred.match(), data, pathArgs)) {
65 private static boolean matchesAny(final Match match, final NormalizedNode data,
66 final Deque<PathArgument> pathArgs) {
67 // Guaranteed to have at least one item
68 final PathArgument pathArg = pathArgs.pop();
69 // Ultimate item -- reuse lookup & match
70 if (pathArgs.isEmpty()) {
71 pathArgs.push(pathArg);
72 return matchesChild(match, data, pathArg);
75 final Optional<NormalizedNode> direct = NormalizedNodes.getDirectChild(data, pathArg);
76 if (direct.isPresent()) {
77 final boolean ret = matchesAny(match, direct.orElseThrow(), pathArgs);
78 pathArgs.push(pathArg);
82 // We may be dealing with a wildcard here. NodeIdentifier is a final class, hence this is as fast as it gets.
83 if (pathArg instanceof NodeIdentifier && data instanceof MapNode) {
84 for (MapEntryNode child : ((MapNode) data).body()) {
85 if (matchesAny(match, child, pathArgs)) {
86 pathArgs.push(pathArg);
92 pathArgs.push(pathArg);
96 private static boolean matchesChild(final Match match, final NormalizedNode data, final PathArgument pathArg) {
97 // Try the direct approach...
98 final Optional<NormalizedNode> direct = NormalizedNodes.getDirectChild(data, pathArg);
99 if (direct.isPresent()) {
100 return match.test(direct.orElseThrow());
103 // We may be dealing with a wildcard here. NodeIdentifier is a final class, hence this is as fast as it gets.
104 if (pathArg instanceof NodeIdentifier && data instanceof MapNode) {
105 for (MapEntryNode child : ((MapNode) data).body()) {
106 if (match.test(child)) {
112 return match.test(null);