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