X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=dom%2Fmdsal-dom-api%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fdom%2Fapi%2Fquery%2FDOMQueryPredicate.java;h=fd6266131b1ccaa5c58e69d2e360ebee10d6bf82;hb=513eb8e5a624d9c09d9f051bbf59ac1ff856bdb7;hp=80db6f34420efd8bced760979e9a1007a30e057e;hpb=6ef51407a2c1731520c3a246442386093e67aeeb;p=mdsal.git diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/query/DOMQueryPredicate.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/query/DOMQueryPredicate.java index 80db6f3442..fd6266131b 100644 --- a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/query/DOMQueryPredicate.java +++ b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/query/DOMQueryPredicate.java @@ -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> { - 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 > Match greaterThan(final T value) { + return new MatchGreaterThan<>(value); + } - abstract static class AbstractValueDOMQueryPredicate extends AbstractLeafDOMQueryPredicate { - private final @NonNull T value; + public static final > 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 > Match lessThan(final T value) { + return new MatchLessThan<>(value); } - final @NonNull T value() { - return value; + public static final > 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 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> - extends AbstractValueDOMQueryPredicate { - AbstractComparableDOMQueryPredicate(final YangInstanceIdentifier relativePath, final T value) { - super(relativePath, value); + private static final class MatchAll extends CompositeMatch { + MatchAll(final ImmutableList 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 { - AbstractStringDOMQueryPredicate(final YangInstanceIdentifier relativePath, final String value) { - super(relativePath, value); + private static final class MatchAny extends CompositeMatch { + MatchAny(final ImmutableList 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 extends AbstractValueDOMQueryPredicate { - public ValueEquals(final YangInstanceIdentifier relativePath, final T value) { - super(relativePath, value); + private static final class MatchValueEquals extends AbstractMatchValue { + 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> extends AbstractComparableDOMQueryPredicate { - 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> extends AbstractMatchComparable { + 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> - extends AbstractComparableDOMQueryPredicate { - public GreaterThanOrEqual(final YangInstanceIdentifier relativePath, final T value) { - super(relativePath, value); + private static final class MatchGreaterThanOrEqual> extends AbstractMatchComparable { + 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> extends AbstractComparableDOMQueryPredicate { - public LessThan(final YangInstanceIdentifier relativePath, final T value) { - super(relativePath, value); + private static final class MatchLessThan> extends AbstractMatchComparable { + 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> extends AbstractComparableDOMQueryPredicate { - public LessThanOrEqual(final YangInstanceIdentifier relativePath, final T value) { - super(relativePath, value); + private static final class MatchLessThanOrEqual> extends AbstractMatchComparable { + 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 components; + + CompositeMatch(final ImmutableList components) { + this.components = requireNonNull(components); + } + + final ImmutableList components() { + return components; + } + + final ImmutableList newComponents(final Match nextComponent) { + return ImmutableList.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 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> extends AbstractMatchValue { + 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 { + 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 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(); } }