*/
@Beta
public interface YangNamespaceContext extends Immutable, Serializable {
+
+
+
/**
* Return the default namespace in this context.
*
--- /dev/null
+/*
+ * Copyright (c) 2019 PANTHEON.tech, 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.Immutable;
+
+/**
+ * An object referencing a QName, either resolved or unresolved.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public interface QNameReferent extends Immutable {
+ /**
+ * Return local name part of the referenced QName.
+ *
+ * @return Local name string.
+ */
+ String getLocalName();
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 PANTHEON.tech, 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;
+
+/**
+ * Common interface for {@link ResolvedQNameReferent} and {@link UnresolvedQNameReferent}, ensuring that only one of
+ * them is implemented by any class.
+ *
+ * @param <T> {@link QNameReferent} behavior subclass
+ */
+interface QNameReferentBehavior<T extends QNameReferentBehavior<T>> extends QNameReferent {
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 PANTHEON.tech, 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.yang.common.QName;
+
+/**
+ * A {@link QNameReferent} referencing a resolved QName.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public interface ResolvedQNameReferent extends QNameReferentBehavior<ResolvedQNameReferent> {
+ /**
+ * Return the referenced QName.
+ *
+ * @return A QName
+ */
+ QName getQName();
+
+ @Override
+ default String getLocalName() {
+ return getQName().getLocalName();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2019 PANTHEON.tech, 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.yang.common.AbstractQName;
+
+/**
+ * A {@link QNameReferent} referencing an unresolved QName.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public interface UnresolvedQNameReferent<T extends ResolvedQNameReferent> extends
+ QNameReferentBehavior<UnresolvedQNameReferent<T>> {
+ /**
+ * Return the referenced {@link AbstractQName}.
+ *
+ * @return An AbstractQName
+ */
+ AbstractQName getQName();
+
+ @Override
+ default String getLocalName() {
+ return getQName().getLocalName();
+ }
+}
import java.util.Objects;
import java.util.Set;
import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.AbstractQName;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
}
}
- public static class QNameStep extends Step {
+ /**
+ * A step along an axis. This may be either a {@link ResolvedQNameStep} or a {@link UnresolvedQNameStep}.
+ *
+ * @author Robert Varga
+ */
+ public abstract static class QNameStep extends Step implements QNameReferent {
+ private static final long serialVersionUID = 1L;
+
+ QNameStep(final YangXPathAxis axis) {
+ super(axis);
+ }
+ }
+
+ public static class ResolvedQNameStep extends QNameStep implements ResolvedQNameReferent {
private static final long serialVersionUID = 1L;
private final QName qname;
- QNameStep(final YangXPathAxis axis, final QName qname) {
+ ResolvedQNameStep(final YangXPathAxis axis, final QName qname) {
super(axis);
this.qname = requireNonNull(qname);
}
+ static ResolvedQNameStep of(final YangXPathAxis axis, final QName qname,
+ final Collection<YangExpr> predicates) {
+ return predicates.isEmpty() ? new ResolvedQNameStep(axis, qname)
+ : new ResolvedQNameStepWithPredicates(axis, qname, ImmutableSet.copyOf(predicates));
+ }
+
+ @Override
public final QName getQName() {
return qname;
}
if (this == obj) {
return true;
}
- if (!(obj instanceof QNameStep)) {
+ if (!(obj instanceof ResolvedQNameStep)) {
return false;
}
- final QNameStep other = (QNameStep) obj;
+ final ResolvedQNameStep other = (ResolvedQNameStep) obj;
return getAxis().equals(other.getAxis()) && qname.equals(other.qname)
&& getPredicates().equals(other.getPredicates());
}
}
}
- static final class QNameStepWithPredicates extends QNameStep {
+ private static final class ResolvedQNameStepWithPredicates extends ResolvedQNameStep {
+ private static final long serialVersionUID = 1L;
+
+ private final ImmutableSet<YangExpr> predicates;
+
+ ResolvedQNameStepWithPredicates(final YangXPathAxis axis, final QName qname,
+ final ImmutableSet<YangExpr> predicates) {
+ super(axis, qname);
+ this.predicates = requireNonNull(predicates);
+ }
+
+ @Override
+ public ImmutableSet<YangExpr> getPredicates() {
+ return predicates;
+ }
+ }
+
+ // FIXME: 4.0.0: integrate this into QName step once QName is a subclass AbstractQName
+ public static class UnresolvedQNameStep extends QNameStep implements UnresolvedQNameReferent<ResolvedQNameStep> {
+ private static final long serialVersionUID = 1L;
+
+ private final AbstractQName qname;
+
+ UnresolvedQNameStep(final YangXPathAxis axis, final AbstractQName qname) {
+ super(axis);
+ this.qname = requireNonNull(qname);
+ }
+
+ static UnresolvedQNameStep of(final YangXPathAxis axis, final AbstractQName qname,
+ final Collection<YangExpr> predicates) {
+ return predicates.isEmpty() ? new UnresolvedQNameStep(axis, qname)
+ : new UnresolvedQNameStepWithPredicates(axis, qname, ImmutableSet.copyOf(predicates));
+ }
+
+ @Override
+ public final AbstractQName getQName() {
+ return qname;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(getAxis(), qname, getPredicates());
+ }
+
+ @Override
+ public final boolean equals(final @Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof UnresolvedQNameStep)) {
+ return false;
+ }
+ final UnresolvedQNameStep other = (UnresolvedQNameStep) obj;
+ return getAxis().equals(other.getAxis()) && qname.equals(other.qname)
+ && getPredicates().equals(other.getPredicates());
+ }
+ }
+
+ private static final class UnresolvedQNameStepWithPredicates extends UnresolvedQNameStep {
private static final long serialVersionUID = 1L;
private final ImmutableSet<YangExpr> predicates;
- QNameStepWithPredicates(final YangXPathAxis axis, final QName qname, final ImmutableSet<YangExpr> predicates) {
+ UnresolvedQNameStepWithPredicates(final YangXPathAxis axis, final AbstractQName qname,
+ final ImmutableSet<YangExpr> predicates) {
super(axis, qname);
this.predicates = requireNonNull(predicates);
}
import com.google.common.annotations.Beta;
import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.AbstractQName;
import org.opendaylight.yangtools.yang.common.QName;
/**
* @author Robert Varga
*/
@Beta
-public final class YangQNameExpr implements YangExpr {
- private static final long serialVersionUID = 1L;
+public abstract class YangQNameExpr implements YangExpr, QNameReferent {
+ public static final class Resolved extends YangQNameExpr implements ResolvedQNameReferent {
+ private static final long serialVersionUID = 1L;
- private final QName qname;
+ private final QName qname;
- private YangQNameExpr(final QName qname) {
- this.qname = requireNonNull(qname);
- }
+ Resolved(final QName qname) {
+ this.qname = requireNonNull(qname);
+ }
+
+ @Override
+ public QName getQName() {
+ return qname;
+ }
+
+ @Override
+ public int hashCode() {
+ return qname.hashCode();
+ }
- public static YangQNameExpr of(final QName qname) {
- return new YangQNameExpr(qname);
+ @Override
+ public boolean equals(final @Nullable Object obj) {
+ return this == obj || obj instanceof Resolved && qname.equals(((Resolved) obj).qname);
+ }
+
+ @Override
+ public String toString() {
+ return qname.toString();
+ }
}
- public QName getQName() {
- return qname;
+ public static final class Unresolved extends YangQNameExpr implements UnresolvedQNameReferent<Resolved> {
+ private static final long serialVersionUID = 1L;
+
+ private final AbstractQName qname;
+
+ Unresolved(final AbstractQName qname) {
+ this.qname = requireNonNull(qname);
+ }
+
+ @Override
+ public AbstractQName getQName() {
+ return qname;
+ }
+
+ @Override
+ public int hashCode() {
+ return qname.hashCode();
+ }
+
+ @Override
+ public boolean equals(final @Nullable Object obj) {
+ return this == obj || obj instanceof Unresolved && qname.equals(((Unresolved) obj).qname);
+ }
+
+ @Override
+ public String toString() {
+ return qname.toString();
+ }
}
- @Override
- public int hashCode() {
- return qname.hashCode();
+ private static final long serialVersionUID = 1L;
+
+ YangQNameExpr() {
+ // Prevent instantiation
}
- @Override
- public boolean equals(final @Nullable Object obj) {
- return this == obj || obj instanceof YangQNameExpr && qname.equals(((YangQNameExpr) obj).qname);
+ public static Unresolved of(final AbstractQName qname) {
+ return new Unresolved(qname);
}
- @Override
- public String toString() {
- return qname.toString();
+ public static Resolved of(final QName qname) {
+ return new Resolved(qname);
}
}
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableSet;
import java.util.Collection;
+import org.opendaylight.yangtools.yang.common.AbstractQName;
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.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;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.ResolvedQNameStep;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.UnresolvedQNameStep;
/**
* XPath evaluation axis, as defined in <a href="https://www.w3.org/TR/1999/REC-xpath-19991116/#axes">XPath 1.0</a>.
}
public final AxisStep asStep(final Collection<YangExpr> predicates) {
- final ImmutableSet<YangExpr> set = ImmutableSet.copyOf(predicates);
- return set.isEmpty() ? step : new AxisStepWithPredicates(this, set);
+ return predicates.isEmpty() ? step : new AxisStepWithPredicates(this, ImmutableSet.copyOf(predicates));
}
- public final QNameStep asStep(final QName qname) {
- return new QNameStep(this, qname);
+ public final ResolvedQNameStep asStep(final QName qname) {
+ return new ResolvedQNameStep(this, qname);
}
- public final QNameStep asStep(final QName qname, final Collection<YangExpr> predicates) {
- final ImmutableSet<YangExpr> set = ImmutableSet.copyOf(predicates);
- return set.isEmpty() ? asStep(qname) : new QNameStepWithPredicates(this, qname, set);
+ public final ResolvedQNameStep asStep(final QName qname, final Collection<YangExpr> predicates) {
+ return ResolvedQNameStep.of(this, qname, predicates);
+ }
+
+ public final UnresolvedQNameStep asStep(final AbstractQName qname) {
+ return new UnresolvedQNameStep(this, qname);
+ }
+
+ public final UnresolvedQNameStep asStep(final AbstractQName qname, final Collection<YangExpr> predicates) {
+ return UnresolvedQNameStep.of(this, qname, predicates);
}
public final NodeTypeStep asStep(final YangXPathNodeType type) {
}
public final NodeTypeStep asStep(final YangXPathNodeType type, final Collection<YangExpr> predicates) {
- final ImmutableSet<YangExpr> set = ImmutableSet.copyOf(predicates);
- return set.isEmpty() ? asStep(type) : new NodeTypeStepWithPredicates(this, type, set);
+ return predicates.isEmpty() ? asStep(type) : new NodeTypeStepWithPredicates(this, type,
+ ImmutableSet.copyOf(predicates));
}
public final ProcessingInstructionStep asStep(final String name) {
}
public final ProcessingInstructionStep asStep(final String name, final Collection<YangExpr> predicates) {
- final ImmutableSet<YangExpr> set = ImmutableSet.copyOf(predicates);
- return set.isEmpty() ? asStep(name) : new ProcessingInstructionStepWithPredicates(this, name, set);
+ return predicates.isEmpty() ? asStep(name) : new ProcessingInstructionStepWithPredicates(this, name,
+ ImmutableSet.copyOf(predicates));
}
@Override
import javax.xml.xpath.XPathExpressionException;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QualifiedQName;
+import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
/**
- * An XPath expression.
+ * An XPath expression. This interface defines a parsed representation of an XPath defined in a YANG context, as
+ * specified in <a href="https://tools.ietf.org/html/rfc7950#section-6.4">RFC7950, Section 6.4</a>.
+ *
+ * <p>
+ * The specification along with rules for {@code path} statement evaluation rules end up defining four incremental
+ * levels to which an XPath expression can be bound:
+ * <ul>
+ * <li>Unbound Expressions, which is a essentially a parse tree. No namespace binding has been performed, i.e. all
+ * node identifiers are in {@link QualifiedQName} or {@link UnqualifiedQName} form. This level is typically not used
+ * when dealing with YANG models directly, but can be useful for validating a String conforms to XPath syntax.
+ * </li>
+ * <li>Qualified-bound Expressions, where all {@link QualifiedQName}s are resolved and bound to {@link QName}s, but
+ * {@link UnqualifiedQName}s are still present. This level corresponds to how far a YANG parser can interpret XPath
+ * expressions defined in {@code typedef} statements and statements which are not fully instantiated, i.e. are
+ * descendants of a {@code grouping} statement.
+ * </li>
+ * <li>Namespace-bound Expressions, where all node identifier references are resolved to {@link QName}s. This level
+ * corresponds to how far a YANG parser can interpret XPath expressions at their place of instantiation, either in
+ * the data tree or an {@code action}/@{code rpc}/{@code notification} or similar context.
+ * </li>
+ * <li>Context-bound Expressions, where the expression is bound to a {code context node}, i.e. {@code current()}
+ * function result is know. This API does not handle this state, as it is inherently bound to a particular data
+ * object model.
+ * </li>
+ * </ul>
*
* @author Robert Varga
*/
@Beta
public interface YangXPathExpression extends Immutable {
+ /**
+ * A Qualified-bound expression. All {@link QualifiedQName}s are eliminated and replaced with {@link QName}s.
+ */
+ interface QualifiedBound extends YangXPathExpression {
+
+ }
+
+ interface UnqualifiedBound extends QualifiedBound {
+ @Override
+ YangQNameExpr.Resolved interpretAsQName(YangLiteralExpr expr) throws XPathExpressionException;
+ }
+
/**
* Return the root {@link YangExpr}.
*
import com.google.common.annotations.Beta;
import javax.xml.xpath.XPathExpressionException;
+import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
/**
* Interface for converting a String into a {@link YangXPathExpression}. Implementations of this interface are expected
*/
@Beta
public interface YangXPathParser {
+ /**
+ * A {@link YangXPathParser} bound to a {@link YangNamespaceContext}, producing Qualified-bound Expressions.
+ */
+ interface QualifiedBound extends YangXPathParser {
+ @Override
+ YangXPathExpression.QualifiedBound parseExpression(String xpath) throws XPathExpressionException;
+ }
+
+ /**
+ * A {@link YangXPathParser} bound to a {@link YangNamespaceContext} and a default namespace, producing
+ * Unqualified-bound Expressions.
+ */
+ interface UnqualifiedBound extends QualifiedBound {
+ @Override
+ YangXPathExpression.UnqualifiedBound parseExpression(String xpath) throws XPathExpressionException;
+ }
+
/**
* Parse a string containing an XPath expression.
*
package org.opendaylight.yangtools.yang.xpath.api;
import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
/**
@Beta
public interface YangXPathParserFactory {
/**
- * Return a {@link YangXPathParser} compliant with {@link YangXPathMathMode#IEEE754}.
+ * Return a {@link YangXPathParser} compliant with {@link YangXPathMathMode#IEEE754}. Returned parser will not
+ * perform any namespace binding.
*
- * @param namespaceContext Prefix-to-namespace resolver
+ * @return An XPathParser
+ */
+ default YangXPathParser newParser() {
+ return newParser(YangXPathMathMode.IEEE754);
+ }
+
+ /**
+ * Return a {@link YangXPathParser} compliant with {@link YangXPathMathMode}. Returned parser will not perform any
+ * namespace binding.
+ *
+ * @param mathMode Requested XPath number compliance
+ * @return An XPathParser
+ * @throws NullPointerException if {@code mathMode} is null
+ */
+ YangXPathParser newParser(YangXPathMathMode mathMode);
+
+ /**
+ * Return a {@link YangXPathParser} compliant with {@link YangXPathMathMode#IEEE754}. Returned parser will bind
+ * qualified node identifiers to {@link QName}s.
+ *
+ * @param namespaceContext Prefix-to-namespace resolver, used to bind qualified node identifiers
* @return An XPathParser
* @throws NullPointerException if {@code namespaceContext} is null
*/
- default YangXPathParser newParser(final YangNamespaceContext namespaceContext) {
- return newParser(namespaceContext, YangXPathMathMode.IEEE754);
+ default YangXPathParser.QualifiedBound newParser(final YangNamespaceContext namespaceContext) {
+ return newParser(YangXPathMathMode.IEEE754, namespaceContext);
+ }
+
+ /**
+ * Return a {@link YangXPathParser} compliant with {@link YangXPathMathMode}. Returned parser will bind qualified
+ * node identifiers to {@link QName}s.
+ *
+ * @param mathMode Requested XPath number compliance
+ * @param namespaceContext Prefix-to-namespace resolver, used to bind qualified node identifiers
+ * @return An XPathParser
+ * @throws NullPointerException if any argument is null
+ */
+ YangXPathParser.QualifiedBound newParser(YangXPathMathMode mathMode, YangNamespaceContext namespaceContext);
+
+ /**
+ * Return a {@link YangXPathParser} compliant with {@link YangXPathMathMode#IEEE754}. Returned parser will bind
+ * qualified and unqualified node identifiers to {@link QName}s.
+ *
+ * @param namespaceContext Prefix-to-namespace resolver, used to bind qualified node identifiers
+ * @param defaultNamespace Default namespace, used to bind unqualified node identifiers
+ * @return An XPathParser
+ * @throws NullPointerException if any argument is null
+ */
+ default YangXPathParser.UnqualifiedBound newParser(final YangNamespaceContext namespaceContext,
+ final QNameModule defaultNamespace) {
+ return newParser(YangXPathMathMode.IEEE754, namespaceContext, defaultNamespace);
}
/**
- * Return a {@link YangXPathParser} compliant with {@link YangXPathMathMode}.
+ * Return a {@link YangXPathParser} compliant with {@link YangXPathMathMode}. Returned parser will bind qualified
+ * and unqualified node identifiers to {@link QName}s.
*
- * @param namespaceContext Prefix-to-namespace resolver
* @param mathMode Requested XPath number compliance
+ * @param namespaceContext Prefix-to-namespace resolver, used to bind qualified node identifiers
+ * @param defaultNamespace Default namespace, used to bind unqualified node identifiers
* @return An XPathParser
* @throws NullPointerException if any argument is null
*/
- YangXPathParser newParser(YangNamespaceContext namespaceContext, YangXPathMathMode mathMode);
+ YangXPathParser.UnqualifiedBound newParser(YangXPathMathMode mathMode, YangNamespaceContext namespaceContext,
+ QNameModule defaultNamespace);
}
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.QualifiedQName;
+import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
import org.opendaylight.yangtools.yang.common.YangConstants;
import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.AxisStep;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.ResolvedQNameStep;
import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
import org.opendaylight.yangtools.yang.xpath.api.YangNaryExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangNaryOperator;
import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.UnaryExprNoRootContext;
import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.UnionExprNoRootContext;
import org.opendaylight.yangtools.yang.xpath.impl.xpathParser.VariableReferenceContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* ANTLR-based XPath parser. Uses {@code xpath.g4} ANTLR grammar.
*
* @author Robert Varga
*/
-final class AntlrXPathParser implements YangXPathParser {
- private static final Logger LOG = LoggerFactory.getLogger(AntlrXPathParser.class);
+abstract class AntlrXPathParser implements YangXPathParser {
+ static class Base extends AntlrXPathParser {
+ Base(final YangXPathMathMode mathMode) {
+ super(mathMode);
+ }
+
+ @Override
+ public YangXPathExpression parseExpression(final String xpath) throws XPathExpressionException {
+ return new AntlrYangXPathExpression.Base(mathMode, parseExpr(xpath), xpath);
+ }
+
+ @Override
+ QNameStep createStep(final YangXPathAxis axis, final String localName,
+ final List<YangExpr> predicates) {
+ return axis.asStep(UnqualifiedQName.of(localName), predicates);
+ }
+
+ @Override
+ QNameStep createStep(final YangXPathAxis axis, final String prefix, final String localName,
+ final List<YangExpr> predicates) {
+ return axis.asStep(QualifiedQName.of(prefix, localName), predicates);
+ }
+
+ @Override
+ QName createQName(final String localName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ QName createQName(final String prefix, final String localName) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ static class Qualified extends Base implements QualifiedBound {
+ final YangNamespaceContext namespaceContext;
+
+ Qualified(final YangXPathMathMode mathMode, final YangNamespaceContext namespaceContext) {
+ super(mathMode);
+ this.namespaceContext = requireNonNull(namespaceContext);
+ }
+
+ @Override
+ public YangXPathExpression.QualifiedBound parseExpression(final String xpath) throws XPathExpressionException {
+ return new AntlrYangXPathExpression.Qualified(mathMode, parseExpr(xpath), xpath, namespaceContext);
+ }
+
+ @Override
+ final QName createQName(final String prefix, final String localName) {
+ return namespaceContext.createQName(prefix, localName);
+ }
+
+ @Override
+ ResolvedQNameStep createStep(final YangXPathAxis axis, final String prefix, final String localName,
+ final List<YangExpr> predicates) {
+ return axis.asStep(createQName(prefix, localName), predicates);
+ }
+ }
+
+ static final class Unqualified extends Qualified implements UnqualifiedBound {
+ private final QNameModule defaultNamespace;
+
+ Unqualified(final YangXPathMathMode mathMode, final YangNamespaceContext namespaceContext,
+ final QNameModule defaultNamespace) {
+ super(mathMode, namespaceContext);
+ this.defaultNamespace = requireNonNull(defaultNamespace);
+ }
+
+ @Override
+ public YangXPathExpression.UnqualifiedBound parseExpression(final String xpath)
+ throws XPathExpressionException {
+ return new AntlrYangXPathExpression.Unqualified(mathMode, parseExpr(xpath), xpath, namespaceContext,
+ defaultNamespace);
+ }
+
+ @Override
+ QName createQName(final String localName) {
+ return QName.create(defaultNamespace, localName);
+ }
+
+ @Override
+ ResolvedQNameStep createStep(final YangXPathAxis axis, final String localName,
+ final List<YangExpr> predicates) {
+ return axis.asStep(QName.create(defaultNamespace, localName), predicates);
+ }
+ }
+
private static final Map<String, YangBinaryOperator> BINARY_OPERATORS = Maps.uniqueIndex(
Arrays.asList(YangBinaryOperator.values()), YangBinaryOperator::toString);
private static final Map<String, YangXPathNodeType> NODE_TYPES = Maps.uniqueIndex(Arrays.asList(
// Cached for checks in hot path
private static final AxisStep SELF_STEP = YangXPathAxis.SELF.asStep();
- private final YangXPathMathMode mathMode;
+ final YangXPathMathMode mathMode;
private final YangXPathMathSupport mathSupport;
- private final YangNamespaceContext namespaceContext;
private final FunctionSupport functionSupport;
- AntlrXPathParser(final YangXPathMathMode mathMode, final YangNamespaceContext namespaceContext) {
+ AntlrXPathParser(final YangXPathMathMode mathMode) {
this.mathMode = requireNonNull(mathMode);
this.mathSupport = mathMode.getSupport();
- this.namespaceContext = requireNonNull(namespaceContext);
- this.functionSupport = new FunctionSupport(namespaceContext, mathSupport);
+ this.functionSupport = new FunctionSupport(mathSupport);
}
- @Override
- public YangXPathExpression parseExpression(final String xpath) throws XPathExpressionException {
+ abstract QName createQName(String localName);
+
+ abstract QName createQName(String prefix, String localName);
+
+ abstract QNameStep createStep(YangXPathAxis axis, String localName, List<YangExpr> predicates);
+
+ abstract QNameStep createStep(YangXPathAxis axis, String prefix, String localName, List<YangExpr> predicates);
+
+ private QNameStep createStep(final YangXPathAxis axis, final QNameContext expr, final List<YangExpr> predicates) {
+ switch (expr.getChildCount()) {
+ case 1:
+ return createStep(axis, getChild(expr, NCNameContext.class, 0).getText(), predicates);
+ case 3:
+ return createStep(axis, getChild(expr, NCNameContext.class, 0).getText(),
+ getChild(expr, NCNameContext.class, 2).getText(), predicates);
+ default:
+ throw illegalShape(expr);
+ }
+ }
+
+ final YangExpr parseExpr(final String xpath) throws XPathExpressionException {
// Create a parser and disconnect it from console error output
final xpathLexer lexer = new xpathLexer(CharStreams.fromString(xpath));
final xpathParser parser = new xpathParser(new CommonTokenStream(lexer));
final YangExpr expr = parseExpr(parser.main().expr());
listener.reportError();
- return new AntlrYangXPathExpression(namespaceContext, mathMode, expr, xpath);
+ return expr;
}
/**
parsed = QName.create(YangConstants.RFC6020_YIN_MODULE, name.getChild(0).getText());
break;
case 3:
- parsed = namespaceContext.createQName(name.getChild(0).getText(), name.getChild(2).getText());
+ parsed = createQName(name.getChild(0).getText(), name.getChild(2).getText());
break;
default:
throw illegalShape(name);
return ret;
}
- private QName parseQName(final QNameContext expr) {
- switch (expr.getChildCount()) {
- case 1:
- return namespaceContext.createQName(getChild(expr, NCNameContext.class, 0).getText());
- case 3:
- return namespaceContext.createQName(getChild(expr, NCNameContext.class, 0).getText(),
- getChild(expr, NCNameContext.class, 2).getText());
- default:
- throw illegalShape(expr);
- }
- }
-
private Step parseStep(final StepContext expr) {
if (expr.getChildCount() == 1) {
final AbbreviatedStepContext abbrev = getChild(expr, AbbreviatedStepContext.class, 0);
verify(((TerminalNode) first).getSymbol().getType() == xpathParser.MUL);
return axis.asStep(predicates);
}
- return axis.asStep(parseQName(verifyTree(QNameContext.class, first)), predicates);
+ return createStep(axis, verifyTree(QNameContext.class, first), predicates);
case 3:
return axis.asStep(parseNodeType(nodeTest.getChild(0)), predicates);
case 4:
}
}
+ private QName parseQName(final QNameContext expr) {
+ switch (expr.getChildCount()) {
+ case 1:
+ return createQName(getChild(expr, NCNameContext.class, 0).getText());
+ case 3:
+ return createQName(getChild(expr, NCNameContext.class, 0).getText(),
+ getChild(expr, NCNameContext.class, 2).getText());
+ default:
+ throw illegalShape(expr);
+ }
+ }
+
private static <T extends ParserRuleContext> T nextContext(final Iterator<ParseTree> it, final Class<T> type) {
return verifyTree(type, it.next());
}
package org.opendaylight.yangtools.yang.xpath.impl;
import org.kohsuke.MetaInfServices;
+import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
import org.opendaylight.yangtools.yang.xpath.api.YangXPathParser;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathParser.QualifiedBound;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathParser.UnqualifiedBound;
import org.opendaylight.yangtools.yang.xpath.api.YangXPathParserFactory;
@MetaInfServices
public final class AntlrXPathParserFactory implements YangXPathParserFactory {
@Override
- public YangXPathParser newParser(final YangNamespaceContext namespaceContext,
- final YangXPathMathMode mathMode) {
- return new AntlrXPathParser(mathMode, namespaceContext);
+ public YangXPathParser newParser(final YangXPathMathMode mathMode) {
+ return new AntlrXPathParser.Base(mathMode);
+ }
+
+ @Override
+ public QualifiedBound newParser(final YangXPathMathMode mathMode, final YangNamespaceContext namespaceContext) {
+ return new AntlrXPathParser.Qualified(mathMode, namespaceContext);
+ }
+
+ @Override
+ public UnqualifiedBound newParser(final YangXPathMathMode mathMode, final YangNamespaceContext namespaceContext,
+ final QNameModule defaultNamespace) {
+ return new AntlrXPathParser.Unqualified(mathMode, namespaceContext, defaultNamespace);
}
}
import static java.util.Objects.requireNonNull;
import javax.xml.xpath.XPathExpressionException;
+import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
+import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr.Resolved;
import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression;
import org.opendaylight.yangtools.yang.xpath.api.YangXPathMathMode;
-final class AntlrYangXPathExpression implements YangXPathExpression {
- private final YangNamespaceContext namespaceContext;
+abstract class AntlrYangXPathExpression implements YangXPathExpression {
+ static final class Base extends AntlrYangXPathExpression {
+ Base(final YangXPathMathMode mathMode, final YangExpr rootExpr, final String origStr) {
+ super(mathMode, rootExpr, origStr);
+ }
+
+ @Override
+ public YangQNameExpr interpretAsQName(final YangLiteralExpr expr) throws XPathExpressionException {
+ return Utils.interpretAsQName(expr);
+ }
+
+ @Override
+ InstanceIdentifierParser createInstanceIdentifierParser() {
+ return new InstanceIdentifierParser.Base(getMathMode());
+ }
+ }
+
+ static class Qualified extends AntlrYangXPathExpression implements QualifiedBound {
+ final YangNamespaceContext namespaceContext;
+
+ Qualified(final YangXPathMathMode mathMode, final YangExpr rootExpr,
+ final String origStr, final YangNamespaceContext namespaceContext) {
+ super(mathMode, rootExpr, origStr);
+ this.namespaceContext = requireNonNull(namespaceContext);
+ }
+
+ YangNamespaceContext getNamespaceContext() {
+ return namespaceContext;
+ }
+
+ @Override
+ public YangQNameExpr interpretAsQName(final YangLiteralExpr expr) throws XPathExpressionException {
+ return Utils.interpretAsQName(namespaceContext, expr);
+ }
+
+ @Override
+ final InstanceIdentifierParser createInstanceIdentifierParser() {
+ return new InstanceIdentifierParser.Qualified(getMathMode(), namespaceContext);
+ }
+ }
+
+ static final class Unqualified extends Qualified implements UnqualifiedBound {
+ private final QNameModule defaultNamespace;
+
+ Unqualified(final YangXPathMathMode mathMode, final YangExpr rootExpr,
+ final String origStr, final YangNamespaceContext namespaceContext, final QNameModule defaultNamespace) {
+ super(mathMode, rootExpr, origStr, namespaceContext);
+ this.defaultNamespace = requireNonNull(defaultNamespace);
+ }
+
+ @Override
+ public Resolved interpretAsQName(final YangLiteralExpr expr) throws XPathExpressionException {
+ return Utils.interpretAsQName(getNamespaceContext(), defaultNamespace, expr);
+ }
+ }
+
private final YangXPathMathMode mathMode;
private final YangExpr rootExpr;
private final String origStr;
- AntlrYangXPathExpression(final YangNamespaceContext namespaceContext, final YangXPathMathMode mathMode,
- final YangExpr rootExpr, final String origStr) {
- this.namespaceContext = requireNonNull(namespaceContext);
+ AntlrYangXPathExpression(final YangXPathMathMode mathMode, final YangExpr rootExpr, final String origStr) {
this.mathMode = requireNonNull(mathMode);
this.rootExpr = requireNonNull(rootExpr);
this.origStr = requireNonNull(origStr);
}
@Override
- public YangXPathMathMode getMathMode() {
+ public final YangXPathMathMode getMathMode() {
return mathMode;
}
@Override
- public YangExpr getRootExpr() {
+ public final YangExpr getRootExpr() {
return rootExpr;
}
@Override
- public YangQNameExpr interpretAsQName(final YangLiteralExpr expr) throws XPathExpressionException {
- return Utils.interpretAsQName(namespaceContext, expr);
+ public final YangLocationPath interpretAsInstanceIdentifier(final YangLiteralExpr expr)
+ throws XPathExpressionException {
+ return createInstanceIdentifierParser().interpretAsInstanceIdentifier(expr);
}
@Override
- public YangLocationPath interpretAsInstanceIdentifier(final YangLiteralExpr expr) throws XPathExpressionException {
- return new InstanceIdentifierParser(namespaceContext, mathMode).interpretAsInstanceIdentifier(expr);
- }
-
- @Override
- public String toString() {
+ public final String toString() {
return origStr;
}
+
+ abstract InstanceIdentifierParser createInstanceIdentifierParser();
}
import static java.util.Objects.requireNonNull;
import java.util.List;
-import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
import org.opendaylight.yangtools.yang.xpath.api.YangBooleanConstantExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangFunction;
YangFunction.STRING_LENGTH.getIdentifier());
private final YangXPathMathSupport mathSupport;
- private final YangNamespaceContext namespaceContext;
- FunctionSupport(final YangNamespaceContext namespaceContext, final YangXPathMathSupport mathSupport) {
- this.namespaceContext = requireNonNull(namespaceContext);
+ FunctionSupport(final YangXPathMathSupport mathSupport) {
this.mathSupport = requireNonNull(mathSupport);
}
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
-import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QualifiedQName;
import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Absolute;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.PredicateContext;
import org.opendaylight.yangtools.yang.xpath.impl.instanceIdentifierParser.QuotedStringContext;
-final class InstanceIdentifierParser {
- private final YangNamespaceContext namespaceContext;
+abstract class InstanceIdentifierParser {
+ static final class Base extends InstanceIdentifierParser {
+ Base(final YangXPathMathMode mathMode) {
+ super(mathMode);
+ }
+
+ @Override
+ YangQNameExpr createExpr(final String prefix, final String localName) {
+ return YangQNameExpr.of(QualifiedQName.of(prefix, localName));
+ }
+
+ @Override
+ QNameStep createChildStep(final String prefix, final String localName, final Collection<YangExpr> predicates) {
+ return YangXPathAxis.CHILD.asStep(QualifiedQName.of(prefix, localName), predicates);
+ }
+ }
+
+ static final class Qualified extends InstanceIdentifierParser {
+ final YangNamespaceContext namespaceContext;
+
+ Qualified(final YangXPathMathMode mathMode, final YangNamespaceContext namespaceContext) {
+ super(mathMode);
+ this.namespaceContext = requireNonNull(namespaceContext);
+ }
+
+ @Override
+ QNameStep createChildStep(final String prefix, final String localName, final Collection<YangExpr> predicates) {
+ return YangXPathAxis.CHILD.asStep(namespaceContext.createQName(prefix, localName), predicates);
+ }
+
+
+ @Override
+ YangQNameExpr createExpr(final String prefix, final String localName) {
+ return YangQNameExpr.of(namespaceContext.createQName(prefix, localName));
+ }
+
+ }
+
private final YangXPathMathSupport mathSupport;
- InstanceIdentifierParser(final YangNamespaceContext namespaceContext, final YangXPathMathMode mathMode) {
- this.namespaceContext = requireNonNull(namespaceContext);
+ InstanceIdentifierParser(final YangXPathMathMode mathMode) {
this.mathSupport = mathMode.getSupport();
}
- Absolute interpretAsInstanceIdentifier(final YangLiteralExpr expr) throws XPathExpressionException {
+ final Absolute interpretAsInstanceIdentifier(final YangLiteralExpr expr) throws XPathExpressionException {
final xpathLexer lexer = new xpathLexer(CharStreams.fromString(expr.getLiteral()));
final instanceIdentifierParser parser = new instanceIdentifierParser(new CommonTokenStream(lexer));
final CapturingErrorListener listener = new CapturingErrorListener();
return YangLocationPath.absolute(steps);
}
- private Step parsePathArgument(final PathArgumentContext expr) {
- final QName qname = parseQName(getChild(expr, NodeIdentifierContext.class, 0));
+ abstract YangQNameExpr createExpr(String prefix, String localName);
+
+ abstract QNameStep createChildStep(String prefix, String localName, Collection<YangExpr> predicates);
+
+ private QNameStep parsePathArgument(final PathArgumentContext expr) {
+ final NodeIdentifierContext childExpr = getChild(expr, NodeIdentifierContext.class, 0);
+ final String prefix = verifyIdentifier(childExpr, 0);
+ final String localName = verifyIdentifier(childExpr, 2);
+
switch (expr.getChildCount()) {
case 1:
- return YangXPathAxis.CHILD.asStep(qname, ImmutableSet.of());
+ return createChildStep(prefix, localName, ImmutableSet.of());
case 2:
- return YangXPathAxis.CHILD.asStep(qname, parsePredicate(getChild(expr, PredicateContext.class, 1)));
+ return createChildStep(prefix, localName, parsePredicate(getChild(expr, PredicateContext.class, 1)));
default:
throw illegalShape(expr);
}
final KeyPredicateExprContext pred = getChild(expr, KeyPredicateContext.class, i)
.getChild(KeyPredicateExprContext.class, 0);
ret.add(YangBinaryOperator.EQUALS.exprWith(
- YangQNameExpr.of(parseQName(getChild(pred, NodeIdentifierContext.class, 0))),
+ createChildExpr(getChild(pred, NodeIdentifierContext.class, 0)),
parseEqStringValue(getChild(pred, EqQuotedStringContext.class, 1))));
}
return ret;
}
- private QName parseQName(final NodeIdentifierContext expr) {
- return namespaceContext.createQName(
- verifyToken(expr, 0, instanceIdentifierParser.Identifier).getText(),
- verifyToken(expr, 2, instanceIdentifierParser.Identifier).getText());
+ private YangQNameExpr createChildExpr(final NodeIdentifierContext expr) {
+ return createExpr(verifyIdentifier(expr, 0), verifyIdentifier(expr, 2));
+ }
+
+ private static String verifyIdentifier(final NodeIdentifierContext expr, final int child) {
+ return verifyToken(expr, child, instanceIdentifierParser.Identifier).getText();
}
private static YangLiteralExpr parseEqStringValue(final EqQuotedStringContext expr) {
import javax.xml.xpath.XPathExpressionException;
import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.AbstractQName;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.QualifiedQName;
+import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
+import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr.Resolved;
+import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr.Unresolved;
/**
* Various simplistic utilities shared across classes.
}
+ static Unresolved interpretAsQName(final YangLiteralExpr expr) throws XPathExpressionException {
+ final String text = expr.getLiteral();
+ final int colon = text.indexOf(':');
+
+ final AbstractQName qname;
+ try {
+ qname = colon != -1 ? QualifiedQName.of(text.substring(0, colon), text.substring(colon + 1))
+ : UnqualifiedQName.of(text);
+ } catch (IllegalArgumentException e) {
+ throw wrapException(e, "Cannot interpret %s as a QName", expr);
+ }
+
+ return YangQNameExpr.of(qname);
+ }
+
static YangQNameExpr interpretAsQName(final YangNamespaceContext namespaceContext, final YangLiteralExpr expr)
throws XPathExpressionException {
final String text = expr.getLiteral();
final int colon = text.indexOf(':');
- final QName qname;
- if (colon != -1) {
- try {
- qname = namespaceContext.createQName(text.substring(0, colon), text.substring(colon + 1));
- } catch (IllegalArgumentException e) {
- throw wrapException(e, "Cannot interpret %s as a QName", expr);
- }
- } else {
- try {
- // Deal with UnprefixedNames by interpreting them in implicit namespace
- qname = namespaceContext.createQName(expr.getLiteral());
- } catch (IllegalArgumentException | IllegalStateException e) {
- throw wrapException(e, "Cannot interpret %s as a QName", expr);
+ try {
+ if (colon == -1) {
+ return YangQNameExpr.of(UnqualifiedQName.of(text));
}
+
+ return YangQNameExpr.of(namespaceContext.createQName(text.substring(0, colon), text.substring(colon + 1)));
+ } catch (IllegalArgumentException e) {
+ throw wrapException(e, "Cannot interpret %s as a QName", expr);
+ }
+ }
+
+ static Resolved interpretAsQName(final YangNamespaceContext namespaceContext,
+ final QNameModule defaultNamespace, final YangLiteralExpr expr) throws XPathExpressionException {
+ final String text = expr.getLiteral();
+ final int colon = text.indexOf(':');
+ final QName qname;
+
+ try {
+ qname = colon == -1 ? QName.create(defaultNamespace, text)
+ : namespaceContext.createQName(text.substring(0, colon), text.substring(colon + 1));
+ } catch (IllegalArgumentException e) {
+ throw wrapException(e, "Cannot interpret %s as a QName", expr);
}
return YangQNameExpr.of(qname);
@Before
public void before() {
- parser = new AntlrXPathParser(YangXPathMathMode.IEEE754, CONTEXT);
+ parser = new AntlrXPathParser.Unqualified(YangXPathMathMode.IEEE754, CONTEXT, DEFNS);
}
@Test