Refactor DOMQueryPredicate 58/93458/5
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 28 Oct 2020 16:50:24 +0000 (17:50 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sat, 31 Oct 2020 19:26:47 +0000 (20:26 +0100)
Refactor aimed at allowing composite predicates without multiple
lookups. While the DOM language allows this use case, the binding
layer does not take advantage of it.

JIRA: MDSAL-617
Change-Id: Ib8a3f77ee660a8c2881d0a18bd0238c6ddce5ade
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/query/AbstractValueMatchBuilder.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/query/DefaultComparableMatchBuilder.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/query/DefaultStringMatchBuilder.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/query/DOMQueryPredicate.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/query/DOMQueryEvaluator.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/query/DOMQueryIterator.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/query/DOMQueryMatcher.java

index 47a32b96bdf0ffba13a639fa6dae1fb0131b955c..080447ffbd3090b732679b8bc73ba6a813d627a6 100644 (file)
@@ -14,8 +14,7 @@ import org.opendaylight.mdsal.binding.api.query.ValueMatch;
 import org.opendaylight.mdsal.binding.api.query.ValueMatchBuilder;
 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.ValueEquals;
+import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.Match;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
@@ -35,26 +34,26 @@ abstract class AbstractValueMatchBuilder<T extends DataObject, V> implements Val
 
     @Override
     public final ValueMatch<T> nonNull() {
-        return withPredicate(new Exists(relativePath()));
+        return withMatch(Match.exists());
     }
 
     @Override
     public final ValueMatch<T> isNull() {
-        return withPredicate(new Exists(relativePath()).negate());
+        return withMatch(Match.exists().negate());
     }
 
     @Override
     public final ValueMatch<T> valueEquals(final V value) {
-        return withPredicate(new ValueEquals<>(relativePath(), value));
+        return withMatch(Match.valueEquals(value));
     }
 
     final YangInstanceIdentifier relativePath() {
         return method.parentPath.node(((DataSchemaNode) method.methodCodec.getSchema()).getQName());
     }
 
-    final @NonNull ValueMatch<T> withPredicate(final DOMQueryPredicate predicate) {
+    final @NonNull ValueMatch<T> withMatch(final Match match) {
         // FIXME: this does not quite take value codec into account :(
-        builder.addPredicate(predicate);
+        builder.addPredicate(DOMQueryPredicate.of(relativePath(), match));
         return new DefaultValueMatch<>(builder, select);
     }
 }
index 64f0382ba089050b801b1e99632fe07b98c6c831..d76937045dc02ba49f467eec91895f666f7a11c4 100644 (file)
@@ -10,10 +10,7 @@ package org.opendaylight.mdsal.binding.dom.adapter.query;
 import org.opendaylight.mdsal.binding.api.query.ComparableMatchBuilder;
 import org.opendaylight.mdsal.binding.api.query.ValueMatch;
 import org.opendaylight.mdsal.binding.dom.adapter.query.QueryBuilderState.BoundMethod;
-import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.GreaterThan;
-import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.GreaterThanOrEqual;
-import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.LessThan;
-import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.LessThanOrEqual;
+import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.Match;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -26,21 +23,21 @@ final class DefaultComparableMatchBuilder<T extends DataObject, V extends Compar
 
     @Override
     public ValueMatch<T> lessThan(final V value) {
-        return withPredicate(new LessThan<>(relativePath(), value));
+        return withMatch(Match.lessThan(value));
     }
 
     @Override
     public ValueMatch<T> lessThanOrEqual(final V value) {
-        return withPredicate(new LessThanOrEqual<>(relativePath(), value));
+        return withMatch(Match.lessThanOrEqual(value));
     }
 
     @Override
     public ValueMatch<T> greaterThan(final V value) {
-        return withPredicate(new GreaterThan<>(relativePath(), value));
+        return withMatch(Match.greaterThan(value));
     }
 
     @Override
     public ValueMatch<T> greaterThanOrEqual(final V value) {
-        return withPredicate(new GreaterThanOrEqual<>(relativePath(), value));
+        return withMatch(Match.greaterThanOrEqual(value));
     }
 }
index 73bc9a3db46bd4403cc139c29b3da4c5bcca3a63..15274c06d1dbe17b1bef38a8b084dea8fec22723 100644 (file)
@@ -11,10 +11,7 @@ import java.util.regex.Pattern;
 import org.opendaylight.mdsal.binding.api.query.StringMatchBuilder;
 import org.opendaylight.mdsal.binding.api.query.ValueMatch;
 import org.opendaylight.mdsal.binding.dom.adapter.query.QueryBuilderState.BoundMethod;
-import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.Contains;
-import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.EndsWith;
-import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.MatchesPattern;
-import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.StartsWith;
+import org.opendaylight.mdsal.dom.api.query.DOMQueryPredicate.Match;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -27,21 +24,21 @@ final class DefaultStringMatchBuilder<T extends DataObject> extends AbstractValu
 
     @Override
     public ValueMatch<T> startsWith(final String str) {
-        return withPredicate(new StartsWith(relativePath(), str));
+        return withMatch(Match.stringStartsWith(str));
     }
 
     @Override
     public ValueMatch<T> endsWith(final String str) {
-        return withPredicate(new EndsWith(relativePath(), str));
+        return withMatch(Match.stringEndsWith(str));
     }
 
     @Override
     public ValueMatch<T> contains(final String str) {
-        return withPredicate(new Contains(relativePath(), str));
+        return withMatch(Match.stringContains(str));
     }
 
     @Override
     public ValueMatch<T> matchesPattern(final Pattern pattern) {
-        return withPredicate(new MatchesPattern(relativePath(), pattern));
+        return withMatch(Match.stringMatches(pattern));
     }
 }
index 80db6f34420efd8bced760979e9a1007a30e057e..fd6266131b1ccaa5c58e69d2e360ebee10d6bf82 100644 (file)
@@ -11,243 +11,470 @@ import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.ImmutableList;
+import java.util.Iterator;
 import java.util.function.Predicate;
 import java.util.regex.Pattern;
 import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
+/**
+ * A single {@link DOMQuery} predicate. It is composed of a relative path and a match. The relative path needs to be
+ * expanded using usual wildcard rules, i.e. NodeIdentifier being used as a 'match all' identifier. For all candidate
+ * nodes selected by the relative path, the corresponding match needs to be invoked.
+ */
 @Beta
-public abstract class DOMQueryPredicate implements Immutable, Predicate<NormalizedNode<?, ?>> {
-    abstract static class AbstractLeafDOMQueryPredicate extends DOMQueryPredicate {
-        AbstractLeafDOMQueryPredicate(final YangInstanceIdentifier relativePath) {
-            super(relativePath);
+@NonNullByDefault
+public final class DOMQueryPredicate implements Immutable {
+    /**
+     * A single match. The primary entrypoint is {@link #test(NormalizedNode)}, but during composition instances may
+     * be combined in a manner similar to {@link Predicate}.
+     */
+    public abstract static class Match {
+        Match() {
+            // Hidden on purpose
         }
 
-        @Override
-        public final boolean test(final NormalizedNode<?, ?> data) {
-            return testValue(data instanceof LeafNode ? ((LeafNode<?>) data).getValue() : null);
+        public static final Match exists() {
+            return MatchExists.INSTACE;
         }
 
-        abstract boolean testValue(Object data);
-    }
+        public static final <T extends Comparable<T>> Match greaterThan(final T value) {
+            return new MatchGreaterThan<>(value);
+        }
 
-    abstract static class AbstractValueDOMQueryPredicate<T> extends AbstractLeafDOMQueryPredicate {
-        private final @NonNull T value;
+        public static final <T extends Comparable<T>> Match greaterThanOrEqual(final T value) {
+            return new MatchGreaterThanOrEqual<>(value);
+        }
 
-        AbstractValueDOMQueryPredicate(final YangInstanceIdentifier relativePath, final T value) {
-            super(relativePath);
-            this.value = requireNonNull(value);
+        public static final <T extends Comparable<T>> Match lessThan(final T value) {
+            return new MatchLessThan<>(value);
         }
 
-        final @NonNull T value() {
-            return value;
+        public static final <T extends Comparable<T>> Match lessThanOrEqual(final T value) {
+            return new MatchLessThanOrEqual<>(value);
+        }
+
+        public static final Match stringMatches(final Pattern pattern) {
+            return new MatchStringMatches(pattern);
+        }
+
+        public static final Match stringStartsWith(final String str) {
+            return new MatchStringStartsWith(str);
+        }
+
+        public static final Match stringEndsWith(final String str) {
+            return new MatchStringEndsWith(str);
+        }
+
+        public static final Match stringContains(final String str) {
+            return new MatchStringContains(str);
+        }
+
+        public static final <V> Match valueEquals(final V value) {
+            return new MatchValueEquals<>(value);
+        }
+
+        /**
+         * Return a {@link Match} which tests the opposite of this match.
+         *
+         * @return Negated match.
+         */
+        public Match negate() {
+            return new MatchNot(this);
+        }
+
+        public Match and(final Match other) {
+            return new MatchAll(ImmutableList.of(this, other));
+        }
+
+        public Match or(final Match other) {
+            return new MatchAny(ImmutableList.of(this, other));
+        }
+
+        public abstract boolean test(@Nullable NormalizedNode<?, ?> data);
+
+        final void appendTo(final StringBuilder sb) {
+            sb.append(op()).append('(');
+            appendArgument(sb);
+            sb.append(')');
+        }
+
+        void appendArgument(final StringBuilder sb) {
+            // No-op by default
         }
 
+        abstract String op();
+
         @Override
-        ToStringHelper addToStringAttributes(final ToStringHelper helper) {
-            return helper.add("value", value);
+        public final String toString() {
+            final var sb = new StringBuilder();
+            appendTo(sb);
+            return sb.toString();
         }
     }
 
-    abstract static class AbstractComparableDOMQueryPredicate<T extends Comparable<T>>
-            extends AbstractValueDOMQueryPredicate<T> {
-        AbstractComparableDOMQueryPredicate(final YangInstanceIdentifier relativePath, final T value) {
-            super(relativePath, value);
+    private static final class MatchAll extends CompositeMatch {
+        MatchAll(final ImmutableList<Match> components) {
+            super(components);
         }
 
         @Override
-        @SuppressWarnings("unchecked")
-        public final boolean testValue(final Object data) {
-            return data != null && test(value().compareTo((T) data));
+        public MatchAll and(final Match other) {
+            return new MatchAll(newComponents(other));
         }
 
-        abstract boolean test(int valueToData);
+        @Override
+        public boolean test(final @Nullable NormalizedNode<?, ?> data) {
+            for (Match component : components()) {
+                if (!component.test(data)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        String op() {
+            return "allOf";
+        }
     }
 
-    abstract static class AbstractStringDOMQueryPredicate extends AbstractValueDOMQueryPredicate<String> {
-        AbstractStringDOMQueryPredicate(final YangInstanceIdentifier relativePath, final String value) {
-            super(relativePath, value);
+    private static final class MatchAny extends CompositeMatch {
+        MatchAny(final ImmutableList<Match> components) {
+            super(components);
         }
 
         @Override
-        public final boolean testValue(final Object data) {
-            return data instanceof String && test((String) data);
+        public MatchAny or(final Match other) {
+            return new MatchAny(newComponents(other));
         }
 
-        abstract boolean test(@NonNull String str);
+        @Override
+        public boolean test(final @Nullable NormalizedNode<?, ?> data) {
+            for (Match component : components()) {
+                if (component.test(data)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        String op() {
+            return "anyOf";
+        }
     }
 
-    public static final class Exists extends DOMQueryPredicate {
-        public Exists(final YangInstanceIdentifier relativePath) {
-            super(relativePath);
+    private static final class MatchExists extends Match {
+        static final MatchExists INSTACE = new MatchExists();
+
+        private MatchExists() {
+            // Hidden on purpose
         }
 
         @Override
-        public boolean test(final NormalizedNode<?, ?> data) {
+        public boolean test(final @Nullable NormalizedNode<?, ?> data) {
             return data != null;
         }
+
+        @Override
+        String op() {
+            return "exists";
+        }
     }
 
-    public static final class Not extends DOMQueryPredicate {
-        private final DOMQueryPredicate predicate;
+    private static final class MatchNot extends Match {
+        private final Match match;
 
-        Not(final DOMQueryPredicate predicate) {
-            super(predicate.relativePath);
-            this.predicate = predicate;
+        MatchNot(final Match match) {
+            this.match = requireNonNull(match);
         }
 
-        public @NonNull DOMQueryPredicate predicate() {
-            return predicate;
+        @Override
+        public Match negate() {
+            return match;
+        }
+
+        @Override
+        public boolean test(final @Nullable NormalizedNode<?, ?> data) {
+            return !match.test(data);
         }
 
         @Override
-        public DOMQueryPredicate negate() {
-            return predicate;
+        String op() {
+            return "not";
         }
 
         @Override
-        public boolean test(final NormalizedNode<?, ?> data) {
-            return !predicate.test(data);
+        void appendArgument(final StringBuilder sb) {
+            match.appendTo(sb);
         }
     }
 
-    public static final class ValueEquals<T> extends AbstractValueDOMQueryPredicate<T> {
-        public ValueEquals(final YangInstanceIdentifier relativePath, final T value) {
-            super(relativePath, value);
+    private static final class MatchValueEquals<T> extends AbstractMatchValue<T> {
+        MatchValueEquals(final T value) {
+            super(value);
         }
 
         @Override
-        public boolean testValue(final Object data) {
+        String op() {
+            return "eq";
+        }
+
+        @Override
+        boolean testValue(final @Nullable Object data) {
             return value().equals(data);
         }
     }
 
-    public static final class GreaterThan<T extends Comparable<T>> extends AbstractComparableDOMQueryPredicate<T> {
-        public GreaterThan(final YangInstanceIdentifier relativePath, final T value) {
-            super(relativePath, value);
+    private static final class MatchStringContains extends AbstractMatchString {
+        MatchStringContains(final String value) {
+            super(value);
+        }
+
+        @Override
+        String op() {
+            return "contains";
+        }
+
+        @Override
+        boolean testString(final String str) {
+            return str.contains(value());
+        }
+    }
+
+    private static final class MatchStringMatches extends AbstractMatch {
+        private final Pattern pattern;
+
+        MatchStringMatches(final Pattern pattern) {
+            this.pattern = requireNonNull(pattern);
+        }
+
+        @Override
+        String op() {
+            return "matches";
+        }
+
+        @Override
+        void appendArgument(final StringBuilder sb) {
+            sb.append(pattern);
+        }
+
+        @Override
+        boolean testValue(final @Nullable Object data) {
+            return data instanceof CharSequence && pattern.matcher((CharSequence) data).matches();
+        }
+    }
+
+    private static final class MatchStringStartsWith extends AbstractMatchString {
+        MatchStringStartsWith(final String value) {
+            super(value);
+        }
+
+        @Override
+        String op() {
+            return "startsWith";
+        }
+
+        @Override
+        boolean testString(final String str) {
+            return str.startsWith(value());
+        }
+    }
+
+    private static final class MatchStringEndsWith extends AbstractMatchString {
+        MatchStringEndsWith(final String value) {
+            super(value);
+        }
+
+        @Override
+        String op() {
+            return "endsWith";
+        }
+
+        @Override
+        boolean testString(final String str) {
+            return str.endsWith(value());
+        }
+    }
+
+    private static final class MatchGreaterThan<T extends Comparable<T>> extends AbstractMatchComparable<T> {
+        MatchGreaterThan(final T value) {
+            super(value);
         }
 
         @Override
-        boolean test(final int valueToData) {
+        String op() {
+            return "gt";
+        }
+
+        @Override
+        boolean testCompare(final int valueToData) {
             return valueToData <= 0;
         }
     }
 
-    public static final class GreaterThanOrEqual<T extends Comparable<T>>
-            extends AbstractComparableDOMQueryPredicate<T> {
-        public GreaterThanOrEqual(final YangInstanceIdentifier relativePath, final T value) {
-            super(relativePath, value);
+    private static final class MatchGreaterThanOrEqual<T extends Comparable<T>> extends AbstractMatchComparable<T> {
+        MatchGreaterThanOrEqual(final T value) {
+            super(value);
         }
 
         @Override
-        boolean test(final int valueToData) {
+        String op() {
+            return "gte";
+        }
+
+        @Override
+        boolean testCompare(final int valueToData) {
             return valueToData < 0;
         }
     }
 
-    public static final class LessThan<T extends Comparable<T>> extends AbstractComparableDOMQueryPredicate<T> {
-        public LessThan(final YangInstanceIdentifier relativePath, final T value) {
-            super(relativePath, value);
+    private static final class MatchLessThan<T extends Comparable<T>> extends AbstractMatchComparable<T> {
+        MatchLessThan(final T value) {
+            super(value);
+        }
+
+        @Override
+        String op() {
+            return "lt";
         }
 
         @Override
-        boolean test(final int valueToData) {
+        boolean testCompare(final int valueToData) {
             return valueToData >= 0;
         }
     }
 
-    public static final class LessThanOrEqual<T extends Comparable<T>> extends AbstractComparableDOMQueryPredicate<T> {
-        public LessThanOrEqual(final YangInstanceIdentifier relativePath, final T value) {
-            super(relativePath, value);
+    private static final class MatchLessThanOrEqual<T extends Comparable<T>> extends AbstractMatchComparable<T> {
+        MatchLessThanOrEqual(final T value) {
+            super(value);
         }
 
         @Override
-        boolean test(final int valueToData) {
+        String op() {
+            return "lte";
+        }
+
+        @Override
+        boolean testCompare(final int valueToData) {
             return valueToData > 0;
         }
     }
 
-    public static final class StartsWith extends AbstractStringDOMQueryPredicate {
-        public StartsWith(final YangInstanceIdentifier relativePath, final String str) {
-            super(relativePath, str);
+    private abstract static class CompositeMatch extends Match {
+        private final ImmutableList<Match> components;
+
+        CompositeMatch(final ImmutableList<Match> components) {
+            this.components = requireNonNull(components);
+        }
+
+        final ImmutableList<Match> components() {
+            return components;
+        }
+
+        final ImmutableList<Match> newComponents(final Match nextComponent) {
+            return ImmutableList.<Match>builderWithExpectedSize(components.size() + 1)
+                .addAll(components)
+                .add(nextComponent)
+                .build();
         }
 
         @Override
-        boolean test(final String str) {
-            return str.startsWith(value());
+        final void appendArgument(final StringBuilder sb) {
+            final Iterator<Match> it = components.iterator();
+            sb.append(it.next());
+            while (it.hasNext()) {
+                sb.append(", ").append(it.next());
+            }
         }
     }
 
-    public static final class EndsWith extends AbstractStringDOMQueryPredicate {
-        public EndsWith(final YangInstanceIdentifier relativePath, final String str) {
-            super(relativePath, str);
+    private abstract static class AbstractMatch extends Match {
+        AbstractMatch() {
+            // Hidden on purpose
         }
 
         @Override
-        boolean test(final String str) {
-            return str.endsWith(value());
+        public final boolean test(final @Nullable NormalizedNode<?, ?> data) {
+            return data instanceof LeafNode ? testValue(((LeafNode<?>) data).getValue()) : testValue(null);
         }
+
+        abstract boolean testValue(@Nullable Object data);
     }
 
-    public static final class Contains extends AbstractStringDOMQueryPredicate {
-        public Contains(final YangInstanceIdentifier relativePath, final String str) {
-            super(relativePath, str);
+    private abstract static class AbstractMatchComparable<T extends Comparable<T>> extends AbstractMatchValue<T> {
+        AbstractMatchComparable(final T value) {
+            super(value);
         }
 
         @Override
-        boolean test(final String str) {
-            return str.contains(value());
+        @SuppressWarnings("unchecked")
+        final boolean testValue(final @Nullable Object data) {
+            return data != null && testCompare(value().compareTo((T) data));
         }
-    }
 
-    public static final class MatchesPattern extends AbstractLeafDOMQueryPredicate {
-        private final Pattern pattern;
+        abstract boolean testCompare(int valueToData);
+    }
 
-        public MatchesPattern(final YangInstanceIdentifier relativePath, final Pattern pattern) {
-            super(relativePath);
-            this.pattern = requireNonNull(pattern);
+    private abstract static class AbstractMatchString extends AbstractMatchValue<String> {
+        AbstractMatchString(final String value) {
+            super(value);
         }
 
         @Override
-        public boolean testValue(final Object data) {
-            return data instanceof CharSequence && pattern.matcher((CharSequence) data).matches();
+        final boolean testValue(final @Nullable Object data) {
+            return data instanceof String && testString((String) data);
+        }
+
+        abstract boolean testString(String str);
+    }
+
+    private abstract static class AbstractMatchValue<T> extends AbstractMatch {
+        private final @NonNull T value;
+
+        AbstractMatchValue(final T value) {
+            this.value = requireNonNull(value);
+        }
+
+        final @NonNull T value() {
+            return value;
         }
 
         @Override
-        ToStringHelper addToStringAttributes(final ToStringHelper helper) {
-            return helper.add("pattern", pattern);
+        final void appendArgument(final StringBuilder sb) {
+            sb.append(value);
         }
     }
 
-    private final @NonNull YangInstanceIdentifier relativePath;
+    private final YangInstanceIdentifier relativePath;
+    private final Match match;
 
-    DOMQueryPredicate(final YangInstanceIdentifier relativePath) {
+    private DOMQueryPredicate(final YangInstanceIdentifier relativePath, final Match match) {
         this.relativePath = requireNonNull(relativePath);
+        this.match = requireNonNull(match);
     }
 
-    public final @NonNull YangInstanceIdentifier getPath() {
-        return relativePath;
+    public static DOMQueryPredicate of(final YangInstanceIdentifier relativePath, final Match match) {
+        return new DOMQueryPredicate(relativePath, match);
     }
 
-    @Override
-    public @NonNull DOMQueryPredicate negate() {
-        return new Not(this);
+    public YangInstanceIdentifier relativePath() {
+        return relativePath;
     }
 
-    @Override
-    public abstract boolean test(@Nullable NormalizedNode<?, ?> data);
+    public Match match() {
+        return match;
+    }
 
     @Override
     public String toString() {
-        return addToStringAttributes(MoreObjects.toStringHelper(this).add("path", relativePath)).toString();
-    }
-
-    ToStringHelper addToStringAttributes(final ToStringHelper helper) {
-        return helper;
+        return MoreObjects.toStringHelper(this).add("path", relativePath).add("match", match).toString();
     }
 }
index 5dceb89b79cc5bada1ce918031fdc75e2eabf5ac..414f615d5a45e8616b6497fa51323fff09d0f64d 100644 (file)
@@ -60,7 +60,7 @@ public final class DOMQueryEvaluator {
     }
 
     private static DOMQueryResult evalSingle(final DOMQuery query, final NormalizedNode<?, ?> data) {
-        return DOMQueryMatcher.matches(data, query.getPredicates()) ? DOMQueryResult.of()
+        return DOMQueryMatcher.matchesAll(data, query.getPredicates()) ? DOMQueryResult.of()
                 : DOMQueryResult.of(new SimpleImmutableEntry<>(query.getRoot(), data));
     }
 }
index e911456d4397dac874fec994762520add9b8f1b4..ff11e8298433bd3758505d69cc50665974433f91 100644 (file)
@@ -329,6 +329,6 @@ final class DOMQueryIterator extends AbstractIterator<Entry<YangInstanceIdentifi
     }
 
     private boolean matches(final NormalizedNode<?, ?> data) {
-        return DOMQueryMatcher.matches(data, predicates);
+        return DOMQueryMatcher.matchesAll(data, predicates);
     }
 }
index 7c9797fd16be59f4a2424fabb2166643cc431005..e5904ecac385c4f297b8fddc4ca3983e8d152ea4 100644 (file)
@@ -12,7 +12,7 @@ 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.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;
@@ -29,7 +29,7 @@ final class DOMQueryMatcher {
         // Utility class
     }
 
-    static boolean matches(final NormalizedNode<?, ?> data, final List<? extends DOMQueryPredicate> predicates) {
+    static boolean matchesAll(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.
@@ -38,13 +38,9 @@ final class DOMQueryMatcher {
             // 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();
+            final YangInstanceIdentifier path = pred.relativePath();
             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())) {
+                if (!matchesChild(pred.match(), data, path.getLastPathArgument())) {
                     return false;
                 }
                 continue;
@@ -57,11 +53,7 @@ final class DOMQueryMatcher {
             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)) {
+            if (!matchesAny(pred.match(), data, pathArgs)) {
                 return false;
             }
 
@@ -70,19 +62,19 @@ final class DOMQueryMatcher {
         return true;
     }
 
-    private static boolean matchesAny(final DOMQueryPredicate pred, final NormalizedNode<?, ?> data,
+    private static boolean matchesAny(final Match match, 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);
+            return matchesChild(match, data, pathArg);
         }
 
         final Optional<NormalizedNode<?, ?>> direct = NormalizedNodes.getDirectChild(data, pathArg);
         if (direct.isPresent()) {
-            final boolean ret = matchesAny(pred, direct.orElseThrow(), pathArgs);
+            final boolean ret = matchesAny(match, direct.orElseThrow(), pathArgs);
             pathArgs.push(pathArg);
             return ret;
         }
@@ -90,7 +82,7 @@ final class DOMQueryMatcher {
         // 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)) {
+                if (matchesAny(match, child, pathArgs)) {
                     pathArgs.push(pathArg);
                     return true;
                 }
@@ -101,23 +93,23 @@ final class DOMQueryMatcher {
         return false;
     }
 
-    private static boolean matchesChild(final DOMQueryPredicate pred, final NormalizedNode<?, ?> data,
+    private static boolean matchesChild(final Match match, 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());
+            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) {
             for (MapEntryNode child : ((MapNode) data).getValue()) {
-                if (pred.test(child)) {
+                if (match.test(child)) {
                     return true;
                 }
             }
         }
 
-        return false;
+        return match.test(null);
     }
 }