Migrate RFC references to rfc-editor.org
[yangtools.git] / model / yang-model-api / src / main / java / org / opendaylight / yangtools / yang / model / api / PathExpression.java
1 /*
2  * Copyright (c) 2019 PANTHEON.tech, s.r.o.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.model.api;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.MoreObjects;
13 import com.google.common.base.MoreObjects.ToStringHelper;
14 import org.eclipse.jdt.annotation.NonNullByDefault;
15 import org.eclipse.jdt.annotation.Nullable;
16 import org.opendaylight.yangtools.concepts.Immutable;
17 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
18 import org.opendaylight.yangtools.yang.xpath.api.YangFunction;
19 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
20 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
21 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Relative;
22 import org.opendaylight.yangtools.yang.xpath.api.YangPathExpr;
23 import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
24 import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression;
25
26 /**
27  * An expression as defined in <a href="https://www.rfc-editor.org/rfc/rfc7950#section-9.9.2">RFC7950 Section 9.9.2</a>,
28  * i.e. the argument of a {@code path} statement.
29  *
30  * <p>
31  * Semantically a {@link PathExpression} is similar to a {@link YangXPathExpression} with guarantees around what
32  * subexpressions it can contain:
33  * <ul>
34  *   <li>the root expression must be a {@link YangLocationPath}</li>
35  *   <li>it can contain steps only along {@link YangXPathAxis#CHILD} and {@link YangXPathAxis#PARENT} axis</li>
36  *   <li>all steps along {@link YangXPathAxis#CHILD} axis are {@link QNameStep}</li>
37  *   <li>the only function invocation is {@link YangFunction#CURRENT}</li>
38  *   <li>only {@link YangBinaryOperator#EQUALS} is allowed</li>
39  *   <li>no literals nor numbers are allowed</li>
40  *   <li>all qualified node identifiers must me resolved</li>
41  * </ul>
42  */
43 @NonNullByDefault
44 public interface PathExpression extends Immutable {
45     /**
46      * Abstract base class for expressing steps of a PathExpression.
47      */
48     abstract sealed class Steps {
49         Steps() {
50             // Prevent external subclassing
51         }
52
53         @Override
54         public abstract int hashCode();
55
56         @Override
57         public abstract boolean equals(@Nullable Object obj);
58
59         @Override
60         public final String toString() {
61             return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
62         }
63
64         abstract ToStringHelper addToStringAttributes(ToStringHelper helper);
65     }
66
67     /**
68      * Steps of a PathExpression which is a LocationPath, corresponding to RFC7950 base specification.
69      */
70     final class LocationPathSteps extends Steps {
71         private final YangLocationPath locationPath;
72
73         public LocationPathSteps(final YangLocationPath locationPath) {
74             this.locationPath = requireNonNull(locationPath);
75         }
76
77         public YangLocationPath getLocationPath() {
78             return locationPath;
79         }
80
81         @Override
82         public int hashCode() {
83             return locationPath.hashCode();
84         }
85
86         @Override
87         public boolean equals(final @Nullable Object obj) {
88             return this == obj || obj instanceof LocationPathSteps other && locationPath.equals(other.locationPath);
89         }
90
91         @Override
92         ToStringHelper addToStringAttributes(final ToStringHelper helper) {
93             return helper.add("locationPath", locationPath);
94         }
95     }
96
97     /**
98      * Steps of a PathExpression which is a combination of {@code deref()} function call and a relative path,
99      * corresponding to Errata 5617.
100      */
101     final class DerefSteps extends Steps {
102         private final Relative derefArgument;
103         private final Relative relativePath;
104
105         public DerefSteps(final Relative derefArgument, final Relative relativePath) {
106             this.derefArgument = requireNonNull(derefArgument);
107             this.relativePath = requireNonNull(relativePath);
108         }
109
110         public Relative getDerefArgument() {
111             return derefArgument;
112         }
113
114         public Relative getRelativePath() {
115             return relativePath;
116         }
117
118         @Override
119         public int hashCode() {
120             return 31 * derefArgument.hashCode() + relativePath.hashCode();
121         }
122
123         @Override
124         public boolean equals(@Nullable final Object obj) {
125             return this == obj || obj instanceof DerefSteps other
126                 && derefArgument.equals(other.derefArgument) && relativePath.equals(other.relativePath);
127         }
128
129         @Override
130         ToStringHelper addToStringAttributes(final ToStringHelper helper) {
131             return helper.add("derefArgument", derefArgument).add("relativePath", relativePath);
132         }
133     }
134
135     /**
136      * Returns the path expression formatted string as is defined in model. For example:
137      * {@code /prefix:container/prefix:container::cond[when()=foo]/prefix:leaf}
138      *
139      * @return the path expression formatted string as is defined in model.
140      */
141     String getOriginalString();
142
143     /**
144      * Return the path of this expression, which can either be a {@link YangLocationPath} (compliant to RFC7950) or
145      * a {@link YangPathExpr} with filter being an invocation of {@link YangFunction#DEREF}.
146      *
147      * @return The path's steps
148      * @throws UnsupportedOperationException if the implementation has not parsed the string. Implementations are
149      *         strongly encouraged to perform proper parsing.
150      */
151     Steps getSteps();
152
153     /**
154      * Returns <code>true</code> if the XPapth starts in root of YANG model, otherwise returns <code>false</code>.
155      *
156      * @return <code>true</code> if the XPapth starts in root of YANG model, otherwise returns <code>false</code>
157      */
158     default boolean isAbsolute() {
159         return getSteps() instanceof LocationPathSteps locationSteps && locationSteps.getLocationPath().isAbsolute();
160     }
161 }