From a531a070e3a9d6a444c00d528bfce072136b3b44 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Fri, 4 May 2018 23:46:12 +0200 Subject: [PATCH] Add yang-xpath-api This patch adds the basic model of a YANG-extended XPath 1.0 expression. JIRA: YANGTOOLS-877 Change-Id: Id5f619e6acd956b7b43f9faba75f34051e3dc509 Signed-off-by: Robert Varga --- common/artifacts/pom.xml | 13 + .../features-yangtools-experimental/pom.xml | 6 + features/odl-yangtools-exp-xpath-api/pom.xml | 49 +++ features/pom.xml | 1 + yang/pom.xml | 3 + yang/yang-xpath-api/pom.xml | 65 +++ .../yang/xpath/api/YangBinaryExpr.java | 65 +++ .../yang/xpath/api/YangBinaryOperator.java | 118 +++++ .../xpath/api/YangBooleanConstantExpr.java | 80 ++++ .../yang/xpath/api/YangConstantExpr.java | 29 ++ .../yangtools/yang/xpath/api/YangExpr.java | 22 + .../yang/xpath/api/YangFilterExpr.java | 90 ++++ .../yang/xpath/api/YangFunction.java | 70 +++ .../yang/xpath/api/YangFunctionCallExpr.java | 109 +++++ .../yang/xpath/api/YangLiteralExpr.java | 80 ++++ .../yang/xpath/api/YangLocationPath.java | 409 ++++++++++++++++++ .../yang/xpath/api/YangNaryExpr.java | 49 +++ .../yang/xpath/api/YangNaryOperator.java | 71 +++ .../yang/xpath/api/YangNegateExpr.java | 47 ++ .../yang/xpath/api/YangNumberExpr.java | 102 +++++ .../yang/xpath/api/YangPathExpr.java | 81 ++++ .../yang/xpath/api/YangPredicateAware.java | 26 ++ .../yang/xpath/api/YangQNameExpr.java | 59 +++ .../xpath/api/YangVariableReferenceExpr.java | 49 +++ .../yang/xpath/api/YangXPathAxis.java | 132 ++++++ .../yang/xpath/api/YangXPathExpression.java | 43 ++ .../yang/xpath/api/YangXPathNodeType.java | 48 ++ .../yang/xpath/api/YangXPathParser.java | 19 + .../xpath/api/YangXPathParserFactory.java | 78 ++++ .../yang/xpath/api/package-info.java | 24 + 30 files changed, 2037 insertions(+) create mode 100644 features/odl-yangtools-exp-xpath-api/pom.xml create mode 100644 yang/yang-xpath-api/pom.xml create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryOperator.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBooleanConstantExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangConstantExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFilterExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunction.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLiteralExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLocationPath.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryOperator.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNegateExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNumberExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPathExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPredicateAware.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangQNameExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangVariableReferenceExpr.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathAxis.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathExpression.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathNodeType.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParser.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParserFactory.java create mode 100644 yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/package-info.java diff --git a/common/artifacts/pom.xml b/common/artifacts/pom.xml index c6920d4328..554944b6af 100644 --- a/common/artifacts/pom.xml +++ b/common/artifacts/pom.xml @@ -206,6 +206,12 @@ 2.0.10-SNAPSHOT + + org.opendaylight.yangtools + yang-xpath-api + 0.1.10-SNAPSHOT + + org.opendaylight.yangtools util @@ -327,6 +333,13 @@ xml features + + org.opendaylight.yangtools + odl-yangtools-exp-xpath-api + 0.1.10-SNAPSHOT + xml + features + diff --git a/features/features-yangtools-experimental/pom.xml b/features/features-yangtools-experimental/pom.xml index 7fab6f6767..8e6047a498 100644 --- a/features/features-yangtools-experimental/pom.xml +++ b/features/features-yangtools-experimental/pom.xml @@ -48,5 +48,11 @@ features xml + + org.opendaylight.yangtools + odl-yangtools-exp-xpath-api + features + xml + diff --git a/features/odl-yangtools-exp-xpath-api/pom.xml b/features/odl-yangtools-exp-xpath-api/pom.xml new file mode 100644 index 0000000000..acd8c80ecd --- /dev/null +++ b/features/odl-yangtools-exp-xpath-api/pom.xml @@ -0,0 +1,49 @@ + + + + 4.0.0 + + + org.opendaylight.odlparent + single-feature-parent + 3.1.3 + + + + org.opendaylight.yangtools + odl-yangtools-exp-xpath-api + 0.1.10-SNAPSHOT + feature + OpenDaylight :: Yangtools :: Experimental :: XPath API + + + + + org.opendaylight.yangtools + yangtools-artifacts + 2.0.10-SNAPSHOT + import + pom + + + + + + + org.opendaylight.yangtools + odl-yangtools-common + xml + features + + + org.opendaylight.yangtools + yang-xpath-api + + + diff --git a/features/pom.xml b/features/pom.xml index dc306ee9d7..21f386ea5d 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -40,6 +40,7 @@ odl-exp-objcache + odl-yangtools-exp-xpath-api features-yangtools-experimental diff --git a/yang/pom.xml b/yang/pom.xml index 316de1113a..f94618d137 100644 --- a/yang/pom.xml +++ b/yang/pom.xml @@ -39,6 +39,9 @@ yang-model-immutable yang-model-util + + yang-xpath-api + yang-model-validator diff --git a/yang/yang-xpath-api/pom.xml b/yang/yang-xpath-api/pom.xml new file mode 100644 index 0000000000..cc15476856 --- /dev/null +++ b/yang/yang-xpath-api/pom.xml @@ -0,0 +1,65 @@ + + + + + + + org.opendaylight.odlparent + bundle-parent + 3.1.3 + + + + 4.0.0 + org.opendaylight.yangtools + yang-xpath-api + 0.1.10-SNAPSHOT + bundle + ${project.artifactId} + YANG XPath ${project.artifactId} + + + + + org.opendaylight.yangtools + yangtools-artifacts + 2.0.10-SNAPSHOT + import + pom + + + + + + + com.google.guava + guava + + + org.opendaylight.yangtools + util + + + org.opendaylight.yangtools + yang-common + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + checkstyle.violationSeverity=error + + + + + diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryExpr.java new file mode 100644 index 0000000000..373b10631f --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryExpr.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import java.util.Objects; +import org.eclipse.jdt.annotation.Nullable; + +/** + * A binary expression formed of a {@link #getLeftExpr()}, an {@link #getOperator()} and a {@link #getRightExpr()}. + * + * @author Robert Varga + */ +@Beta +public abstract class YangBinaryExpr implements YangExpr { + private static final long serialVersionUID = 1L; + + private final YangExpr leftExpr; + private final YangExpr rightExpr; + + YangBinaryExpr(final YangExpr leftExpr, final YangExpr rightExpr) { + this.leftExpr = requireNonNull(leftExpr); + this.rightExpr = requireNonNull(rightExpr); + } + + public final YangExpr getLeftExpr() { + return leftExpr; + } + + public final YangExpr getRightExpr() { + return rightExpr; + } + + public abstract YangBinaryOperator getOperator(); + + @Override + public final int hashCode() { + return Objects.hash(leftExpr, rightExpr, getOperator()); + } + + @Override + public final boolean equals(final @Nullable Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof YangBinaryExpr)) { + return false; + } + final YangBinaryExpr other = (YangBinaryExpr) obj; + return getOperator().equals(other.getOperator()) && leftExpr.equals(other.leftExpr) + && rightExpr.equals(other.rightExpr); + } + + @Override + public final String toString() { + return leftExpr.toString() + " " + getOperator() + " " + rightExpr; + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryOperator.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryOperator.java new file mode 100644 index 0000000000..2718716222 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBinaryOperator.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; + +/** + * YANG XPath binary operator. + * + * @author Robert Varga + */ +@Beta +public enum YangBinaryOperator { + /** + * Operands are equal. + * + * @see EqualityExpr + */ + EQUALS("="), + /** + * Operands do not equal. + * + * @see EqualityExpr + */ + NOT_EQUALS("!="), + + /** + * Left-hand operand is greater than right-hand operand. + * + * @see RelationalExpr + */ + GT(">"), + /** + * Left-hand operand is greater than or equal to right-hand operand. + * + * @see RelationalExpr + */ + GTE(">="), + /** + * Left-hand operand is less than right-hand operand. + * + * @see RelationalExpr + */ + LT("<"), + /** + * Left-hand operand is less than or equal to right-hand operand. + * + * @see RelationalExpr + */ + LTE("<="), + + /** + * Arithmetic addition. + * + * @see AdditiveExpr + */ + PLUS("+"), + /** + * Arithmetic subtraction. + * + * @see AdditiveExpr + */ + MINUS("-"), + + /** + * Arithmetic multiplication. + * + * @see MultiplicativeExpr + */ + MUL("*"), + /** + * Arithmetic division. + * + * @see MultiplicativeExpr + */ + DIV("div"), + /** + * Arithmetic modulus after truncating division. + * + * @see MultiplicativeExpr + */ + MOD("mod"); + + private final class Expr extends YangBinaryExpr { + private static final long serialVersionUID = 1L; + + Expr(final YangExpr leftExpr, final YangExpr rightExpr) { + super(leftExpr, rightExpr); + } + + @Override + public YangBinaryOperator getOperator() { + return YangBinaryOperator.this; + } + } + + private final String str; + + YangBinaryOperator(final String str) { + this.str = requireNonNull(str); + } + + @Override + public String toString() { + return str; + } + + public YangBinaryExpr exprWith(final YangExpr leftExpr, final YangExpr rightExpr) { + return new Expr(leftExpr, rightExpr); + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBooleanConstantExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBooleanConstantExpr.java new file mode 100644 index 0000000000..cd7f8d77fa --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangBooleanConstantExpr.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import java.util.Optional; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.yang.common.QName; + +/** + * Expressions which evaluate to a logical {@code true} or {@code false}. These expressions are equivalent to the result + * returned by {@code true()} and {@code false()} functions defined in XPath 1.0. + * + *

+ * They also map these functions' names to the constant pool under their {@link YangFunctionCallExpr#getName()} + * identity. All users should use these constants in favor of their equivalent function calls. + * + * @author Robert Varga + */ +@Beta +public enum YangBooleanConstantExpr implements YangConstantExpr { + /** + * A constant {@code false} expression. + */ + FALSE(Boolean.FALSE, YangFunction.FALSE), + /** + * A constant {@code true} expression. + */ + TRUE(Boolean.TRUE, YangFunction.TRUE); + + private final YangFunctionCallExpr function; + private final Boolean value; + + @SuppressWarnings("null") + YangBooleanConstantExpr(final @Nullable Boolean value, final YangFunction function) { + this.value = requireNonNull(value); + this.function = YangFunctionCallExpr.of(function.getIdentifier()); + } + + @Override + public QName getIdentifier() { + return function.getName(); + } + + @Override + public Boolean getValue() { + return value; + } + + /** + * Convert this constant into the equivalent function. This function is provided for bridging purposes only. + * + * @return Equivalent function invocation. + */ + public YangFunctionCallExpr asFunction() { + return function; + } + + public static YangBooleanConstantExpr of(final boolean bool) { + return bool ? TRUE : FALSE; + } + + public static Optional forFunctionName(final String functionName) { + switch (functionName) { + case "false": + return Optional.of(FALSE.function); + case "true": + return Optional.of(TRUE.function); + default: + return Optional.empty(); + } + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangConstantExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangConstantExpr.java new file mode 100644 index 0000000000..26336f755a --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangConstantExpr.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import com.google.common.annotations.Beta; +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.yang.common.QName; + +/** + * Common interface for all YANG XPath constant expressions. Each constant has a unique {@link QName}, which acts as its + * globally-unique identifier. + * + * @author Robert Varga + */ +@Beta +public interface YangConstantExpr extends YangExpr, Identifiable { + /** + * Return this constant's value. + * + * @return this constant's value. + */ + // FIXME: this seems dicey w.r.t. empty nodeset constant. + T getValue(); +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangExpr.java new file mode 100644 index 0000000000..6ef826cfb3 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangExpr.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import com.google.common.annotations.Beta; +import java.io.Serializable; +import org.opendaylight.yangtools.concepts.Immutable; + +/** + * Common base interface for all YANG Expression components. + * + * @author Robert Varga + */ +@Beta +public interface YangExpr extends Immutable, Serializable { + +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFilterExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFilterExpr.java new file mode 100644 index 0000000000..7343e569ff --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFilterExpr.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableSet; +import java.util.Arrays; +import java.util.Collection; +import java.util.Objects; +import java.util.Set; +import org.eclipse.jdt.annotation.Nullable; + +@Beta +public class YangFilterExpr implements YangExpr, YangPredicateAware { + private static final class WithPredicates extends YangFilterExpr { + private static final long serialVersionUID = 1L; + + private final Set predicates; + + WithPredicates(final YangExpr expr, final Set predicates) { + super(expr); + this.predicates = requireNonNull(predicates); + } + + @Override + public Set getPredicates() { + return predicates; + } + } + + private static final long serialVersionUID = 1L; + + private final YangExpr expr; + + private YangFilterExpr(final YangExpr expr) { + this.expr = requireNonNull(expr); + } + + public static YangFilterExpr of(final YangExpr expr) { + return new YangFilterExpr(expr); + } + + public static YangFilterExpr of(final YangExpr expr, final YangExpr... predicates) { + return of(expr, Arrays.asList(predicates)); + } + + public static YangFilterExpr of(final YangExpr expr, final Collection predicates) { + return predicates.isEmpty() ? new YangFilterExpr(expr) + : new WithPredicates(expr, ImmutableSet.copyOf(predicates)); + } + + public final YangExpr getExpr() { + return expr; + } + + @Override + public Set getPredicates() { + return ImmutableSet.of(); + } + + @Override + public final int hashCode() { + return Objects.hash(expr, getPredicates()); + } + + @Override + public final boolean equals(final @Nullable Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof YangFilterExpr)) { + return false; + } + final YangFilterExpr other = (YangFilterExpr) obj; + return expr.equals(((YangFilterExpr) obj).expr) && getPredicates().equals(other.getPredicates()); + } + + @Override + public final String toString() { + // FIXME: this is not right + return "-(" + expr + ")"; + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunction.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunction.java new file mode 100644 index 0000000000..7e893eb146 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunction.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import com.google.common.annotations.Beta; +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.YangConstants; + +/** + * Functions known to a YANG XPath. + * + * @author Robert Varga + */ +@Beta +public enum YangFunction implements Identifiable { + // XPath 1.0 functions + BOOLEAN("boolean"), + CEILING("ceiling"), + CONCAT("concat"), + CONTAINS("contains"), + COUNT("count"), + FALSE("false"), + FLOOR("floor"), + ID("id"), + LANG("lang"), + LAST("last"), + LOCAL_NAME("local-name"), + NAME("name"), + NUMBER("number"), + NAMESPACE_URI("namespace-uri"), + NORMALIZE_SPACE("normalize-space"), + NOT("not"), + POSITION("position"), + ROUND("round"), + STARTS_WITH("starts-with"), + STRING("string"), + STRING_LENGTH("string-length"), + SUM("sum"), + SUBSTRING("substring"), + SUBSTRING_AFTER("substring-after"), + SUBSTRING_BEFORE("substring-before"), + TRANSLATE("translate"), + TRUE("true"), + + // RFC7950 functions + BIT_IS_SET("bit-is-set"), + CURRENT("current"), + DEREF("deref"), + DERIVED_FROM("derived-from"), + DERIVED_FROM_OR_SELF("derived-from-or-self"), + ENUM_VALUE("enum-value"), + RE_MATCH("re-match"); + + private final QName identifier; + + YangFunction(final String localName) { + identifier = QName.create(YangConstants.RFC6020_YIN_MODULE, localName).intern(); + } + + @Override + public QName getIdentifier() { + return identifier; + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java new file mode 100644 index 0000000000..4cf1fbf4af --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangFunctionCallExpr.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.YangConstants; + +/** + * Function call invocation. Function names without a prefix are mapped into {@link YangConstants#RFC6020_YIN_MODULE}, + * as they are required to be mapped into YANG as per RFC7950 definitions. + * + * @author Robert Varga + */ +@Beta +public abstract class YangFunctionCallExpr implements YangExpr { + static class NoArgs extends YangFunctionCallExpr { + private static final long serialVersionUID = 1L; + + private final QName name; + + NoArgs(final QName name) { + this.name = requireNonNull(name); + } + + @Override + public QName getName() { + return name; + } + } + + private static final class WithArgs extends NoArgs { + private static final long serialVersionUID = 1L; + + private final List arguments; + + WithArgs(final QName name, final List arguments) { + super(name); + this.arguments = ImmutableList.copyOf(arguments); + } + + @Override + public List getArguments() { + return arguments; + } + } + + private static final long serialVersionUID = 1L; + + YangFunctionCallExpr() { + // Hidden + } + + public static YangFunctionCallExpr of(final QName name) { + return new NoArgs(name); + } + + public static YangFunctionCallExpr of(final QName name, final List arguments) { + return arguments.isEmpty() ? of(name) : new WithArgs(name, arguments); + } + + public abstract QName getName(); + + public List getArguments() { + return ImmutableList.of(); + } + + @Override + public final int hashCode() { + return Objects.hash(getName(), getArguments()); + } + + @Override + public final boolean equals(final @Nullable Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof YangFunctionCallExpr)) { + return false; + } + final YangFunctionCallExpr other = (YangFunctionCallExpr) obj; + return getName().equals(other.getName()) && getArguments().equals(other.getArguments()); + } + + @Override + public final String toString() { + final StringBuilder sb = new StringBuilder().append(getName()).append('('); + final Iterator it = getArguments().iterator(); + if (it.hasNext()) { + sb.append(it.next()); + while (it.hasNext()) { + sb.append(", ").append(it.next()); + } + } + return sb.append(')').toString(); + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLiteralExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLiteralExpr.java new file mode 100644 index 0000000000..1ece060f05 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLiteralExpr.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.Nullable; + +/** + * An XPath literal expression. + * + *

+ * Note that a literal may be required to hold a value of {@code instance-identifier} or {@code identityref} type, + * when the corresponding {@link YangXPathExpression} was parsed from reference String specification defined in RFC7950. + * When such conversion is required, it should be performed through + * {@link YangXPathExpression#interpretAsQName(YangLiteralExpr)} or + * {@link YangXPathExpression#interpretAsInstanceIdentifier(YangLiteralExpr)}. + * + *

+ * A more type-safe alternative is {@link YangQNameExpr}, which should be preferred and used whenever possible. + * + * @author Robert Varga + */ +@Beta +public class YangLiteralExpr implements YangExpr { + private static final class Empty extends YangLiteralExpr { + private static final long serialVersionUID = 1L; + + Empty() { + super(""); + } + + @SuppressWarnings("static-method") + Object readResolve() { + return empty(); + } + } + + private static final long serialVersionUID = 1L; + private static final YangLiteralExpr EMPTY = new Empty(); + + private final String literal; + + protected YangLiteralExpr(final String literal) { + this.literal = requireNonNull(literal); + } + + public static final YangLiteralExpr empty() { + return EMPTY; + } + + public static final YangLiteralExpr of(final String literal) { + return literal.isEmpty() ? EMPTY : new YangLiteralExpr(literal); + } + + public final String getLiteral() { + return literal; + } + + @Override + public final int hashCode() { + return literal.hashCode(); + } + + @Override + public final boolean equals(final @Nullable Object obj) { + return this == obj || obj instanceof YangLiteralExpr && literal.equals(((YangLiteralExpr) obj).literal); + } + + @Override + public final String toString() { + return literal; + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLocationPath.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLocationPath.java new file mode 100644 index 0000000000..be9351f96f --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangLocationPath.java @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +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.io.Serializable; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.common.QNameModule; + +@Beta +public class YangLocationPath implements YangExpr { + public abstract static class Step implements Serializable, YangPredicateAware { + private static final long serialVersionUID = 1L; + + private final YangXPathAxis axis; + + Step(final YangXPathAxis axis) { + this.axis = requireNonNull(axis); + } + + public final YangXPathAxis getAxis() { + return axis; + } + + @Override + public abstract int hashCode(); + + @Override + public abstract boolean equals(@Nullable Object obj); + + @Override + public final String toString() { + return addToStringAttributes(MoreObjects.toStringHelper(this)).toString(); + } + + protected ToStringHelper addToStringAttributes(final ToStringHelper helper) { + helper.add("axis", axis); + final Set predicates = getPredicates(); + if (!predicates.isEmpty()) { + helper.add("predicates", predicates); + } + return helper; + } + } + + public static class AxisStep extends Step { + private static final long serialVersionUID = 1L; + + AxisStep(final YangXPathAxis axis) { + super(axis); + } + + @Override + public final int hashCode() { + return Objects.hash(getAxis(), getPredicates()); + } + + @Override + public final boolean equals(@Nullable final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof AxisStep)) { + return false; + } + final AxisStep other = (AxisStep) obj; + return getAxis().equals(other.getAxis()) && getPredicates().equals(other.getPredicates()); + } + + private Object readResolve() { + return getAxis().asStep(); + } + } + + static final class AxisStepWithPredicates extends AxisStep { + private static final long serialVersionUID = 1L; + + private final Set predicates; + + AxisStepWithPredicates(final YangXPathAxis axis, final Set predicates) { + super(axis); + this.predicates = requireNonNull(predicates); + } + + @Override + public Set getPredicates() { + return predicates; + } + } + + // match a particular namespace + public static class NamespaceStep extends Step { + private static final long serialVersionUID = 1L; + + private final QNameModule namespace; + + NamespaceStep(final YangXPathAxis axis, final QNameModule namespace) { + super(axis); + this.namespace = requireNonNull(namespace); + } + + public final QNameModule getNamespace() { + return namespace; + } + + @Override + public final int hashCode() { + return Objects.hash(getAxis(), namespace, getPredicates()); + } + + @Override + public final boolean equals(@Nullable final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof NamespaceStep)) { + return false; + } + final NamespaceStep other = (NamespaceStep) obj; + return getAxis().equals(other.getAxis()) && namespace.equals(other.namespace) + && getPredicates().equals(other.getPredicates()); + } + + @Override + protected ToStringHelper addToStringAttributes(final ToStringHelper helper) { + return super.addToStringAttributes(helper).add("namespace", namespace); + } + } + + public static class QNameStep extends Step { + private static final long serialVersionUID = 1L; + + private final QName qname; + + QNameStep(final YangXPathAxis axis, final QName qname) { + super(axis); + this.qname = requireNonNull(qname); + } + + public final QName getQName() { + return qname; + } + + @Override + public final int hashCode() { + return Objects.hash(getAxis(), qname, getPredicates()); + } + + @Override + public final boolean equals(@Nullable final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof QNameStep)) { + return false; + } + final QNameStep other = (QNameStep) obj; + return getAxis().equals(other.getAxis()) && qname.equals(other.qname) + && getPredicates().equals(other.getPredicates()); + } + + @Override + protected ToStringHelper addToStringAttributes(final ToStringHelper helper) { + return super.addToStringAttributes(helper).add("qname", qname); + } + } + + static final class QNameStepWithPredicates extends QNameStep { + private static final long serialVersionUID = 1L; + + private final Set predicates; + + QNameStepWithPredicates(final YangXPathAxis axis, final QName qname, final Set predicates) { + super(axis, qname); + this.predicates = requireNonNull(predicates); + } + + @Override + public Set getPredicates() { + return predicates; + } + } + + public static class NodeTypeStep extends Step { + private static final long serialVersionUID = 1L; + + private final YangXPathNodeType nodeType; + + NodeTypeStep(final YangXPathAxis axis, final YangXPathNodeType nodeType) { + super(axis); + this.nodeType = requireNonNull(nodeType); + } + + public final YangXPathNodeType getNodeType() { + return nodeType; + } + + @Override + public int hashCode() { + return Objects.hash(getAxis(), nodeType, getPredicates()); + } + + @Override + public boolean equals(@Nullable final Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !getClass().equals(obj.getClass())) { + return false; + } + final NodeTypeStep other = (NodeTypeStep) obj; + return nodeType.equals(other.nodeType) && getAxis().equals(other.getAxis()) + && getPredicates().equals(other.getPredicates()); + } + + @Override + protected ToStringHelper addToStringAttributes(final ToStringHelper helper) { + return super.addToStringAttributes(helper).add("nodeType", nodeType); + } + } + + static final class NodeTypeStepWithPredicates extends NodeTypeStep { + private static final long serialVersionUID = 1L; + + private final Set predicates; + + NodeTypeStepWithPredicates(final YangXPathAxis axis, final YangXPathNodeType type, + final Set predicates) { + super(axis, type); + this.predicates = requireNonNull(predicates); + } + + @Override + public Set getPredicates() { + return predicates; + } + } + + public static class ProcessingInstructionStep extends NodeTypeStep { + private static final long serialVersionUID = 1L; + + private final String name; + + ProcessingInstructionStep(final YangXPathAxis axis, final String name) { + super(axis, YangXPathNodeType.PROCESSING_INSTRUCTION); + this.name = requireNonNull(name); + } + + public final String getName() { + return name; + } + + @Override + public final int hashCode() { + return Objects.hash(getAxis(), getNodeType(), name, getPredicates()); + } + + @Override + public final boolean equals(final @Nullable Object obj) { + return obj == this || super.equals(obj) && name.equals(((ProcessingInstructionStep) obj).name); + } + + @Override + protected ToStringHelper addToStringAttributes(final ToStringHelper helper) { + return super.addToStringAttributes(helper).add("name", name); + } + } + + static final class ProcessingInstructionStepWithPredicates extends ProcessingInstructionStep { + private static final long serialVersionUID = 1L; + + private final Set predicates; + + ProcessingInstructionStepWithPredicates(final YangXPathAxis axis, final String name, + final Set predicates) { + super(axis, name); + this.predicates = requireNonNull(predicates); + } + + @Override + public Set getPredicates() { + return predicates; + } + } + + public static class Absolute extends YangLocationPath { + private static final long serialVersionUID = 1L; + + @Override + public final boolean isAbsolute() { + return true; + } + } + + private static final class AbsoluteWithSteps extends Absolute { + private static final long serialVersionUID = 1L; + + private final List steps; + + AbsoluteWithSteps(final List steps) { + this.steps = requireNonNull(steps); + } + + @Override + public List getSteps() { + return steps; + } + } + + private static final class WithSteps extends YangLocationPath { + private static final long serialVersionUID = 1L; + + private final List steps; + + WithSteps(final List steps) { + this.steps = requireNonNull(steps); + } + + @Override + public List getSteps() { + return steps; + } + } + + private static final long serialVersionUID = 1L; + private static final YangLocationPath ROOT = new Absolute(); + private static final YangLocationPath SELF = new YangLocationPath(); + + YangLocationPath() { + // Hidden to prevent external instantiation + } + + public static final YangLocationPath of(final boolean absolute) { + return absolute ? ROOT : SELF; + } + + public static final YangLocationPath of(final boolean absolute, final Step... steps) { + return of(absolute, Arrays.asList(steps)); + } + + public static final YangLocationPath of(final boolean absolute, final Collection steps) { + if (steps.isEmpty()) { + return of(absolute); + } + + final List copy = ImmutableList.copyOf(steps); + return absolute ? new AbsoluteWithSteps(copy) : new WithSteps(copy); + } + + /** + * The conceptual {@code root} {@link YangLocationPath}. This path is an absolute path and has no steps. + * + * @return Empty absolute {@link YangLocationPath} + */ + public static final YangLocationPath root() { + return ROOT; + } + + /** + * The conceptual {@code same} {@link YangLocationPath}. This path is a relative path and has no steps and is + * equivalent to a step along {@link YangXPathAxis#SELF}. + * + * @return Empty relative {@link YangLocationPath} + */ + public static YangLocationPath self() { + return SELF; + } + + public boolean isAbsolute() { + return false; + } + + public List getSteps() { + return ImmutableList.of(); + } + + @Override + public final int hashCode() { + return Boolean.hashCode(isAbsolute()) * 31 + getSteps().hashCode(); + } + + @Override + public final boolean equals(final @Nullable Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof YangLocationPath)) { + return false; + } + final YangLocationPath other = (YangLocationPath) obj; + return isAbsolute() == other.isAbsolute() && getSteps().equals(other.getSteps()); + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryExpr.java new file mode 100644 index 0000000000..a59705c7a6 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryExpr.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import java.util.Objects; +import java.util.Set; +import org.eclipse.jdt.annotation.Nullable; + +@Beta +public abstract class YangNaryExpr implements YangExpr { + private static final long serialVersionUID = 1L; + + private final Set expressions; + + YangNaryExpr(final Set expressions) { + this.expressions = requireNonNull(expressions); + } + + public final Set getExpressions() { + return expressions; + } + + public abstract YangNaryOperator getOperator(); + + @Override + public final int hashCode() { + return Objects.hash(getOperator(), expressions); + } + + @Override + public final boolean equals(final @Nullable Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof YangNaryExpr)) { + return false; + } + final YangNaryExpr other = (YangNaryExpr) obj; + return getOperator().equals(other.getOperator()) && expressions.equals(other.expressions); + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryOperator.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryOperator.java new file mode 100644 index 0000000000..84c94d5ca8 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNaryOperator.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableSet; +import java.util.Collection; +import java.util.Set; + +/** + * YANG XPath binary operator. + * + * @author Robert Varga + */ +@Beta +public enum YangNaryOperator { + /** + * Logical 'and' operator on operands. + * + * @see AndExpr + */ + AND("and"), + /** + * Logical 'or' operator on operands. + * + * @see OrExpr + */ + OR("or"), + /** + * Set union operator on operands. + * + * @see UnionExpr + */ + UNION("|"); + + private final class Expr extends YangNaryExpr { + private static final long serialVersionUID = 1L; + + Expr(final Set exprs) { + super(exprs); + } + + @Override + public YangNaryOperator getOperator() { + return YangNaryOperator.this; + } + } + + private final String str; + + YangNaryOperator(final String str) { + this.str = requireNonNull(str); + } + + @Override + public String toString() { + return str; + } + + public YangExpr exprWith(final Collection exprs) { + final Set set = ImmutableSet.copyOf(exprs); + return set.size() == 1 ? set.iterator().next() : new Expr(set); + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNegateExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNegateExpr.java new file mode 100644 index 0000000000..41fd77f9a1 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNegateExpr.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.Nullable; + +@Beta +public final class YangNegateExpr implements YangExpr { + private static final long serialVersionUID = 1L; + + private final YangExpr subExpr; + + private YangNegateExpr(final YangExpr subExpr) { + this.subExpr = requireNonNull(subExpr); + } + + public static YangNegateExpr of(final YangExpr subExpr) { + return new YangNegateExpr(subExpr); + } + + public YangExpr getSubExpr() { + return subExpr; + } + + @Override + public int hashCode() { + return subExpr.hashCode(); + } + + @Override + public boolean equals(final @Nullable Object obj) { + return this == obj || obj instanceof YangNegateExpr && subExpr.equals(((YangNegateExpr) obj).subExpr); + } + + @Override + public String toString() { + return "-(" + subExpr + ")"; + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNumberExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNumberExpr.java new file mode 100644 index 0000000000..85deadb77d --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangNumberExpr.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import java.math.BigDecimal; +import org.eclipse.jdt.annotation.Nullable; + +/** + * A number-bearing expression. + */ +@Beta +public abstract class YangNumberExpr, N extends Number> implements YangExpr { + public static final class YangBigDecimal extends YangNumberExpr { + private static final long serialVersionUID = 1L; + + private final BigDecimal number; + + YangBigDecimal(final BigDecimal number) { + this.number = requireNonNull(number); + } + + @Override + public BigDecimal getNumber() { + return number; + } + + @Override + public int hashCode() { + return number.hashCode(); + } + + @Override + public boolean equals(final @Nullable Object obj) { + return this == obj || obj instanceof YangBigDecimal + && number.equals(((YangBigDecimal) obj).number); + } + + @Override + public String toString() { + return number.toString(); + } + } + + public static final class YangDouble extends YangNumberExpr { + private static final long serialVersionUID = 1L; + + private final double value; + + YangDouble(final double value) { + this.value = value; + } + + public double getValue() { + return value; + } + + @Override + public Double getNumber() { + return value; + } + + @Override + public int hashCode() { + return Double.hashCode(value); + } + + @Override + public boolean equals(final @Nullable Object obj) { + return this == obj || obj instanceof YangDouble && value == ((YangDouble) obj).value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + } + + + private static final long serialVersionUID = 1L; + + YangNumberExpr() { + // Hidden to prevent external subclassing + } + + public static YangBigDecimal of(final BigDecimal number) { + return new YangBigDecimal(number); + } + + public static YangDouble of(final double value) { + return new YangDouble(value); + } + + public abstract N getNumber(); +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPathExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPathExpr.java new file mode 100644 index 0000000000..d695d2ec41 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPathExpr.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import java.util.Objects; +import java.util.Optional; +import org.eclipse.jdt.annotation.Nullable; + +@Beta +public class YangPathExpr implements YangExpr { + private static final class WithLocation extends YangPathExpr { + private static final long serialVersionUID = 1L; + + private final YangLocationPath locationPath; + + WithLocation(final YangExpr filterExpr, final YangLocationPath locationPath) { + super(filterExpr); + this.locationPath = requireNonNull(locationPath); + } + + @Override + public Optional getLocationPath() { + return Optional.of(locationPath); + } + } + + private static final long serialVersionUID = 1L; + + private final YangExpr filterExpr; + + YangPathExpr(final YangExpr filterExpr) { + this.filterExpr = requireNonNull(filterExpr); + } + + public static YangPathExpr of(final YangExpr filterExpr) { + return new YangPathExpr(filterExpr); + } + + public static YangExpr of(final YangExpr expr, final YangLocationPath locationPath) { + return new WithLocation(expr, locationPath); + } + + public final YangExpr getFilterExpr() { + return filterExpr; + } + + public Optional getLocationPath() { + return Optional.empty(); + } + + @Override + public final int hashCode() { + return Objects.hash(filterExpr, getLocationPath()); + } + + @Override + public final boolean equals(final @Nullable Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof YangPathExpr)) { + return false; + } + final YangPathExpr other = (YangPathExpr) obj; + return filterExpr.equals(((YangPathExpr) obj).filterExpr) && getLocationPath().equals(other.getLocationPath()); + } + + @Override + public final String toString() { + // FIXME: this is not right + return "-(" + filterExpr + ")"; + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPredicateAware.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPredicateAware.java new file mode 100644 index 0000000000..fd07ec215a --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangPredicateAware.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableSet; +import java.util.Set; +import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step; + +/** + * Common interface for {@link YangFilterExpr} and {@link Step}, both of which can contain predicates. Predicates are + * expressed in terms of {@link YangExpr}. + * + * @author Robert Varga + */ +@Beta +public interface YangPredicateAware { + default Set getPredicates() { + return ImmutableSet.of(); + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangQNameExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangQNameExpr.java new file mode 100644 index 0000000000..c1306a1299 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangQNameExpr.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.yang.common.QName; + +/** + * An XPath QName expression. This is an exact QName, which cannot be converted to a string literal compatible with + * XPath string representation, because it does not define a prefix/namespace mapping. It represents a strong binding + * to a particular namespace at a particular revision. + * + *

+ * Parsers and users of this package are encouraged to use this class in place of {@link YangLiteralExpr} where + * appropriate, as it retains type safety and more semantic context. + * + * @author Robert Varga + */ +@Beta +public final class YangQNameExpr implements YangExpr { + private static final long serialVersionUID = 1L; + + private final QName qname; + + private YangQNameExpr(final QName qname) { + this.qname = requireNonNull(qname); + } + + public static YangQNameExpr of(final QName qname) { + return new YangQNameExpr(qname); + } + + public QName getQName() { + return qname; + } + + @Override + public int hashCode() { + return qname.hashCode(); + } + + @Override + public boolean equals(final @Nullable Object obj) { + return this == obj || obj instanceof YangQNameExpr && qname.equals(((YangQNameExpr) obj).qname); + } + + @Override + public String toString() { + return qname.toString(); + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangVariableReferenceExpr.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangVariableReferenceExpr.java new file mode 100644 index 0000000000..ec7c1124b2 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangVariableReferenceExpr.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.yang.common.QName; + +@Beta +public final class YangVariableReferenceExpr implements YangExpr { + private static final long serialVersionUID = 1L; + + private final QName variableName; + + private YangVariableReferenceExpr(final QName variableName) { + this.variableName = requireNonNull(variableName); + } + + public static YangVariableReferenceExpr of(final QName variableName) { + return new YangVariableReferenceExpr(variableName); + } + + public QName getVariableName() { + return variableName; + } + + @Override + public int hashCode() { + return variableName.hashCode(); + } + + @Override + public boolean equals(final @Nullable Object obj) { + return this == obj || obj instanceof YangVariableReferenceExpr + && variableName.equals(((YangVariableReferenceExpr) obj).variableName); + } + + @Override + public String toString() { + return "$" + variableName; + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathAxis.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathAxis.java new file mode 100644 index 0000000000..452102c2c0 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathAxis.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableSet; +import java.util.Collection; +import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.AxisStep; +import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.AxisStepWithPredicates; +import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.NodeTypeStep; +import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.NodeTypeStepWithPredicates; +import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.ProcessingInstructionStep; +import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.ProcessingInstructionStepWithPredicates; +import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep; +import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStepWithPredicates; + +/** + * XPath evaluation axis, as defined in XPath 1.0. + * + * @author Robert Varga + */ +@Beta +public enum YangXPathAxis { + /** + * The {@code child} axis. + */ + CHILD("child"), + /** + * The {@code descendant} axis. + */ + DESCENDANT("descendant"), + /** + * The {@code parent} axis. + */ + PARENT("parent"), + /** + * The {@code ancestor} axis. + */ + ANCESTOR("ancestor"), + /** + * The {@code following-sibling} axis. + */ + FOLLOWING_SIBLING("following-sibling"), + /** + * The {@code preceding-sibling} axis. + */ + PRECEDING_SIBLING("preceding-sibling"), + /** + * The {@code following} axis. + */ + FOLLOWING("following"), + /** + * The {@code preceding} axis. + */ + PRECEDING("preceding"), + /** + * The {@code attribute} axis. + */ + ATTRIBUTE("attribute"), + /** + * The {@code namespace} axis. + */ + NAMESPACE("namespace"), + /** + * The {@code self} axis. + */ + SELF("self"), + /** + * The {@code descendant-or-self} axis. + */ + DESCENDANT_OR_SELF("descendant-or-self"), + /** + * The {@code ancestor-or-self} axis. + */ + ANCESTOR_OR_SELF("ancestor-or-self"); + + private final AxisStep step = new AxisStep(this); + private final String str; + + YangXPathAxis(final String str) { + this.str = requireNonNull(str); + } + + /** + * Return the name-independent {@link AxisStep} along this axis. XPath defines following axis {@code AxisStep}s: + *

+ * other axes have these defined as a courtesy. + * + * @return Name-independent AnyNameStep. + */ + public final AxisStep asStep() { + return step; + } + + public final AxisStep asStep(final Collection predicates) { + final ImmutableSet set = ImmutableSet.copyOf(predicates); + return set.isEmpty() ? step : new AxisStepWithPredicates(this, set); + } + + public final QNameStep asStep(final QName qname, final Collection predicates) { + final ImmutableSet set = ImmutableSet.copyOf(predicates); + return set.isEmpty() ? new QNameStep(this, qname) : new QNameStepWithPredicates(this, qname, set); + } + + public final NodeTypeStep asStep(final YangXPathNodeType type, final Collection predicates) { + final ImmutableSet set = ImmutableSet.copyOf(predicates); + return set.isEmpty() ? new NodeTypeStep(this, type) : new NodeTypeStepWithPredicates(this, type, set); + } + + public final ProcessingInstructionStep asStep(final String name, final Collection predicates) { + final ImmutableSet set = ImmutableSet.copyOf(predicates); + return set.isEmpty() ? new ProcessingInstructionStep(this, name) + : new ProcessingInstructionStepWithPredicates(this, name, set); + } + + @Override + public String toString() { + return str; + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathExpression.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathExpression.java new file mode 100644 index 0000000000..91d3e7c37d --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathExpression.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import com.google.common.annotations.Beta; +import javax.xml.xpath.XPathExpressionException; +import org.opendaylight.yangtools.concepts.Immutable; +import org.opendaylight.yangtools.yang.common.QName; + +@Beta +public interface YangXPathExpression extends Immutable { + + YangExpr getRootExpr(); + + /** + * Attempt to interpret a {@link YangLiteralExpr} referenced by this expression as a {@link QName}. This method + * is required to perform late value binding of the expression when the literal needs to be interpreted as + * a reference to an {@code identity}. + * + *

+ * The syntax of expr is required to conform to + * XML QName format, as further restricted by + * YANG {@code identityref} Lexical Representation. + * + *

+ * Unfortunately we do not know when a literal will need to be interpreted in this way, as that can only be known + * at evaluation. + * + * @param expr Literal to be reinterpreted + * @return QName representation of the literal + * @throws XPathExpressionException when the literal cannot be interpreted as a QName + */ + QName interpretAsQName(YangLiteralExpr expr) throws XPathExpressionException; + + // API design: this really should be YangInstanceIdentifier without AugmentationIdentifier. Implementations are + // strongly encouraged to validate it as such. + YangLocationPath interpretAsInstanceIdentifier(YangLiteralExpr expr) throws XPathExpressionException; +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathNodeType.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathNodeType.java new file mode 100644 index 0000000000..62f40ecb22 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathNodeType.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, 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.yangtools.yang.xpath.api; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; + +/** + * XPath node type as defined in XPath 1.0. + * + * @author Robert Varga + */ +@Beta +public enum YangXPathNodeType { + /** + * A {@code comment}. + */ + COMMENT("comment"), + /** + * A {@code text}. + */ + TEXT("text"), + /** + * A {@code processing-instruction}. + */ + PROCESSING_INSTRUCTION("processing-instruction"), + /** + * A {@code node}. + */ + NODE("node"); + + private final String str; + + YangXPathNodeType(final String str) { + this.str = requireNonNull(str); + } + + @Override + public String toString() { + return str; + } +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParser.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParser.java new file mode 100644 index 0000000000..f0e594909a --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParser.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import com.google.common.annotations.Beta; +import javax.annotation.concurrent.NotThreadSafe; +import javax.xml.xpath.XPathExpressionException; + +@Beta +@NotThreadSafe +public interface YangXPathParser { + + YangXPathExpression parseExpression(String xpath) throws XPathExpressionException; +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParserFactory.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParserFactory.java new file mode 100644 index 0000000000..77a02ff01b --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/YangXPathParserFactory.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.yangtools.yang.xpath.api; + +import com.google.common.annotations.Beta; +import java.util.Set; +import java.util.function.Function; +import javax.annotation.concurrent.ThreadSafe; +import org.opendaylight.yangtools.yang.common.QNameModule; + +/** + * Factory for creating {@link YangXPathParser}s. + * + * @author Robert Varga + */ +@Beta +@ThreadSafe +public interface YangXPathParserFactory { + /** + * {@link YangXPathParser} number compliance knobs. This enumeration defines what assumptions the parser can make -- + * affecting its optimization properties around + * constant folding when number expressions are + * involved. + */ + @Beta + enum MathMode { + /** + * All number expressions are treated as {@code double}. This in spirit of XPath 1.0 -- any number expression + * starts its life as a double, making all operations subject to IEEE754 rounding and range rules. + */ + IEEE754, + + /** + * All number expressions are treated as infinite-precision numbers. This follows the spirit of YANG 1.1 -- + * where mostly have integral types and decimal64 mapped to BigDecimal. Non-decimal numbers are mapped either to + * {@code int}, {@code long} or {@code BigInteger}. + */ + EXACT, + + /* + * FIXME: 3.0.0: specify and implement this: + * + * All number expressions are treated either as {@code org.opendaylight.yangtools.yang.common} types with + * precision required to hold them. Decimal types are mapped to {@link Decimal64} with all range restrictions + * and rounding error implied by it. + */ + // ODL_COMMON, + } + + Set getSupportedMathModes(); + + /** + * Return a {@link YangXPathParser} compliant with {@link MathMode#IEEE754}. + * + * @param prefixResolver Prefix-to-namespace resolver function + * @return An XPathParser + * @throws IllegalArgumentException if {@code IEEE754} is not supported. + */ + default YangXPathParser newParser(final Function prefixResolver) { + return newParser(prefixResolver, MathMode.IEEE754); + } + + /** + * Return a {@link YangXPathParser} compliant with {@link MathMode}. + * + * @param prefixResolver Prefix-to-namespace resolver function + * @param mathMode Requested XPath number compliance + * @return An XPathParser + * @throws NullPointerException if {@code mathMode} is null + * @throws IllegalArgumentException if {@code mathMode} is not supported. + */ + YangXPathParser newParser(Function prefixResolver, MathMode mathMode); +} diff --git a/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/package-info.java b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/package-info.java new file mode 100644 index 0000000000..c883d78688 --- /dev/null +++ b/yang/yang-xpath-api/src/main/java/org/opendaylight/yangtools/yang/xpath/api/package-info.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, 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 + */ +/** + * Model of a RFC7950 XPath Expression. This model is namespace-bound to a particular set of models as conveyed + * by their {@link org.opendaylight.yangtools.yang.common.QNameModule}s. Function names are bound either to their + * defining {@link org.opendaylight.yangtools.yang.common.QName}, unprefixed functions are bound to + * {@link org.opendaylight.yangtools.yang.common.YangConstants#RFC6020_YIN_MODULE} the same way unprefixed statements + * are. + * + *

+ * The model supports multiple number storage and math operations -- with IEEE754 being the default as per XPath 1.0 + * specifications, but additional exact operations being available. + * + * @author Robert Varga + */ +@NonNullByDefault +package org.opendaylight.yangtools.yang.xpath.api; + +import org.eclipse.jdt.annotation.NonNullByDefault; \ No newline at end of file -- 2.36.6