import org.opendaylight.mdsal.binding.dom.adapter.query.QueryBuilderState.BoundMethod;
import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate;
import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.Exists;
+import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.NotExists;
import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.ValueEquals;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@Override
public final ValueMatch<T> isNull() {
- return withPredicate(new Exists(relativePath()).negate());
+ return withPredicate(new NotExists(relativePath()));
}
@Override
import org.opendaylight.mdsal.binding.api.query.QueryFactory;
import org.opendaylight.mdsal.binding.api.query.QueryResult;
import org.opendaylight.mdsal.binding.api.query.QueryResult.Item;
+import org.opendaylight.mdsal.binding.api.query.QueryStructureException;
import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
import org.opendaylight.yang.gen.v1.mdsal.query.norev.FooBuilder;
import org.opendaylight.yang.gen.v1.mdsal.query.norev.first.grp.System;
import org.opendaylight.yang.gen.v1.mdsal.query.norev.first.grp.SystemBuilder;
-import org.opendaylight.yang.gen.v1.mdsal.query.norev.first.grp.SystemKey;
import org.opendaylight.yang.gen.v1.mdsal.query.norev.second.grp.Alarms;
import org.opendaylight.yang.gen.v1.mdsal.query.norev.second.grp.AlarmsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.Top;
}
@Test
- public void bar() {
+ public void bar() throws QueryStructureException {
final Stopwatch sw = Stopwatch.createStarted();
final QueryExpression<TopLevelList> query = factory.querySubtree(InstanceIdentifier.create(Top.class))
.extractChild(TopLevelList.class)
}
@Test
- public void testFindCriticalAlarms() {
+ public void testFindCriticalAlarms() throws QueryStructureException {
final Stopwatch sw = Stopwatch.createStarted();
final QueryExpression<Alarms> query = factory.querySubtree(InstanceIdentifier.create(Foo.class))
.extractChild(System.class)
}
@Test
- public void testFindNonCriticalAlarms() {
+ public void testFindNonCriticalAlarms() throws QueryStructureException {
final Stopwatch sw = Stopwatch.createStarted();
final QueryExpression<Alarms> query = factory.querySubtree(InstanceIdentifier.create(Foo.class))
.extractChild(System.class)
}
@Test
- public void testFindZeroAlarms() {
+ public void testFindZeroAlarms() throws QueryStructureException {
final Stopwatch sw = Stopwatch.createStarted();
final QueryExpression<Alarms> query = factory.querySubtree(InstanceIdentifier.create(Foo.class))
.extractChild(System.class)
assertEquals(2, items.size());
}
- @Test
- public void testFindSystemFirstAlarmOne() {
- final Stopwatch sw = Stopwatch.createStarted();
- final QueryExpression<Alarms> query = factory.querySubtree(InstanceIdentifier.create(Foo.class))
- .extractChild(System.class, new SystemKey("first"))
- .extractChild(Alarms.class)
- .matching()
- .leaf(Alarms::getId).valueEquals(Uint64.ZERO)
- .build();
- LOG.info("Query built in {}", sw);
-
- final List<? extends Item<@NonNull Alarms>> items = execute(query).getItems();
- assertEquals(1, items.size());
- }
-
- @Test
- public void testFindSystemFirstWithAlarmOne() {
- final Stopwatch sw = Stopwatch.createStarted();
- final QueryExpression<System> query = factory.querySubtree(InstanceIdentifier.create(Foo.class))
- .extractChild(System.class, new SystemKey("first"))
- .matching()
- .childObject(Alarms.class)
- .leaf(Alarms::getId).valueEquals(Uint64.ZERO)
- .build();
- LOG.info("Query built in {}", sw);
-
- final List<? extends Item<@NonNull System>> items = execute(query).getItems();
- assertEquals(1, items.size());
- }
-
-
private <T extends @NonNull DataObject> QueryResult<T> execute(final QueryExpression<T> query) {
final Stopwatch sw = Stopwatch.createStarted();
final QueryResult<T> result = executor.executeQuery(query);
}
}
- public static final class Not extends DOMQueryPredicate {
- private final DOMQueryPredicate predicate;
-
- Not(final DOMQueryPredicate predicate) {
- super(predicate.relativePath);
- this.predicate = predicate;
- }
-
- public @NonNull DOMQueryPredicate predicate() {
- return predicate;
- }
-
- @Override
- public DOMQueryPredicate negate() {
- return predicate;
+ public static final class NotExists extends DOMQueryPredicate {
+ public NotExists(final YangInstanceIdentifier relativePath) {
+ super(relativePath);
}
@Override
public boolean test(final NormalizedNode<?, ?> data) {
- return !predicate.test(data);
+ return data == null;
}
}
return relativePath;
}
- @Override
- public @NonNull DOMQueryPredicate negate() {
- return new Not(this);
- }
-
@Override
public abstract boolean test(@Nullable NormalizedNode<?, ?> data);
}
private static DOMQueryResult evalSingle(final DOMQuery query, final NormalizedNode<?, ?> data) {
- return DOMQueryMatcher.matches(data, query.getPredicates()) ? DOMQueryResult.of()
+ return LazyDOMQueryResultIterator.matches(data, query.getPredicates()) ? DOMQueryResult.of()
: DOMQueryResult.of(new SimpleImmutableEntry<>(query.getRoot(), data));
}
}
+++ /dev/null
-/*
- * 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.Not;
-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 LazyDOMQueryResultIterator} for simplicity.
- */
-final class DOMQueryMatcher {
- private DOMQueryMatcher() {
- // Utility class
- }
-
- static boolean matches(final NormalizedNode<?, ?> data, final List<? extends DOMQueryPredicate> 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<PathArgument> 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.getPath();
- if (path.coerceParent().isEmpty()) {
- if (pred instanceof Not) {
- if (matchesChild(((Not) pred).predicate(), data, path.getLastPathArgument())) {
- return false;
- }
- } else if (!matchesChild(pred, 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 (pred instanceof Not) {
- if (matchesAny(((Not) pred).predicate(), data, pathArgs)) {
- return false;
- }
- } else if (!matchesAny(pred, data, pathArgs)) {
- return false;
- }
-
- pathArgs.clear();
- }
- return true;
- }
-
- private static boolean matchesAny(final DOMQueryPredicate pred, final NormalizedNode<?, ?> data,
- final Deque<PathArgument> 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(pred, data, pathArg);
- }
-
- final Optional<NormalizedNode<?, ?>> direct = NormalizedNodes.getDirectChild(data, pathArg);
- if (direct.isPresent()) {
- final boolean ret = matchesAny(pred, 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) {
- for (MapEntryNode child : ((MapNode) data).getValue()) {
- if (matchesAny(pred, child, pathArgs)) {
- pathArgs.push(pathArg);
- return true;
- }
- }
- }
-
- pathArgs.push(pathArg);
- return false;
- }
-
- private static boolean matchesChild(final DOMQueryPredicate pred, final NormalizedNode<?, ?> data,
- final PathArgument pathArg) {
- // Try the direct approach...
- final Optional<NormalizedNode<?, ?>> direct = NormalizedNodes.getDirectChild(data, pathArg);
- if (direct.isPresent()) {
- return pred.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) {
- for (MapEntryNode child : ((MapNode) data).getValue()) {
- if (pred.test(child)) {
- return true;
- }
- }
- }
-
- return false;
- }
-}
import org.opendaylight.mdsal.dom.api.query.DOMQuery;
import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
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;
// This is the ultimate step in lookup, process it without churning the stack by imposing a dedicated
// Frame. In either case we are done with this frame, unwinding it in both cases.
if (matches(child)) {
- return unwindAndReturn(current, next, child);
+ final YangInstanceIdentifier childPath = createIdentifier(child);
+ unwind(current, next);
+ return new SimpleImmutableEntry<>(childPath, child);
}
current = unwind(current, next);
// Push our state back, it's just a placeholder for 'currentSelect'. Current path points at us and so does
// the saved Frame.
currentPath.addLast(current.data.getIdentifier());
+ frames.push(current);
// Now decide what sort of entry to push. For maps we want to start an iterator already, so it gets
// picked up as a continuation.
- if (child instanceof MapNode) {
- final MapNode map = (MapNode) child;
- final PathArgument target = remainingSelect.peek();
- if (target instanceof NodeIdentifierWithPredicates) {
- final Optional<MapEntryNode> optEntry = map.getChild((NodeIdentifierWithPredicates) target);
- if (optEntry.isPresent()) {
- final MapEntryNode entry = optEntry.orElseThrow();
- if (remainingSelect.size() != 1) {
- // We need to perform further selection push this frame, an empty frame for the map and
- // finally a frame for the map entry.
- remainingSelect.pop();
- frames.push(current);
- currentPath.addLast(map.getIdentifier());
- frames.push(new Frame(map, next));
- current = new Frame(entry, target);
- continue;
- }
-
- // We have selected entry, see it it matches. In any case rewind, potentially returning
- // the match
- if (matches(entry)) {
- return unwindAndReturn(current, next, entry);
- }
- }
-
- // We failed to find a matching entry, unwind
- current = unwind(current, next);
- continue;
- }
-
- // We have a wildcard, expand it
- frames.push(current);
- current = new MapFrame(child, next, map.getValue().iterator());
- } else {
- // Next step in iteration, deal with it
- frames.push(current);
- current = new Frame(child, next);
- }
+ current = child instanceof MapNode ? new MapFrame(child, next, ((MapNode) child).getValue().iterator())
+ : new Frame(child, next);
}
// All done, there be entries no more.
return new SimpleImmutableEntry<>(childPath, child);
}
- // Unwind any leftover frames and return a matching item
- private Entry<YangInstanceIdentifier, NormalizedNode<?, ?>> unwindAndReturn(final Frame frame,
- final PathArgument next, final NormalizedNode<?, ?> child) {
- final YangInstanceIdentifier childPath = createIdentifier(child);
- unwind(frame, next);
- return new SimpleImmutableEntry<>(childPath, child);
- }
-
/**
* Unwind the stack, discarding current frame, and possibly some others. The unwind starts with pushing {@code next}
* to {@link #remainingSelect}, hence we remember to handle it next time around. It then defers to
}
private boolean matches(final NormalizedNode<?, ?> data) {
- return DOMQueryMatcher.matches(data, predicates);
+ return matches(data, predicates);
+ }
+
+ static boolean matches(final NormalizedNode<?, ?> data, final List<? extends DOMQueryPredicate> predicates) {
+ for (DOMQueryPredicate pred : predicates) {
+ // Okay, now we need to deal with predicates, but do it in a smart fashion, so we do not end up iterating
+ // all over the place. Typically we will be matching just a leaf.
+ final YangInstanceIdentifier path = pred.getPath();
+ final Optional<NormalizedNode<?, ?>> node;
+ if (path.coerceParent().isEmpty()) {
+ node = NormalizedNodes.getDirectChild(data, path.getLastPathArgument());
+ } else {
+ node = NormalizedNodes.findNode(data, path);
+ }
+
+ if (!pred.test(node.orElse(null))) {
+ return false;
+ }
+ }
+ return true;
}
}