Add yang-xpath-api
[yangtools.git] / yang / yang-xpath-api / src / main / java / org / opendaylight / yangtools / yang / xpath / api / YangLocationPath.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, 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.xpath.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 com.google.common.collect.ImmutableList;
16 import java.io.Serializable;
17 import java.util.Arrays;
18 import java.util.Collection;
19 import java.util.List;
20 import java.util.Objects;
21 import java.util.Set;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.common.QNameModule;
25
26 @Beta
27 public class YangLocationPath implements YangExpr {
28     public abstract static class Step implements Serializable, YangPredicateAware {
29         private static final long serialVersionUID = 1L;
30
31         private final YangXPathAxis axis;
32
33         Step(final YangXPathAxis axis) {
34             this.axis = requireNonNull(axis);
35         }
36
37         public final YangXPathAxis getAxis() {
38             return axis;
39         }
40
41         @Override
42         public abstract int hashCode();
43
44         @Override
45         public abstract boolean equals(@Nullable Object obj);
46
47         @Override
48         public final String toString() {
49             return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
50         }
51
52         protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
53             helper.add("axis", axis);
54             final Set<YangExpr> predicates = getPredicates();
55             if (!predicates.isEmpty()) {
56                 helper.add("predicates", predicates);
57             }
58             return helper;
59         }
60     }
61
62     public static class AxisStep extends Step {
63         private static final long serialVersionUID = 1L;
64
65         AxisStep(final YangXPathAxis axis) {
66             super(axis);
67         }
68
69         @Override
70         public final int hashCode() {
71             return Objects.hash(getAxis(), getPredicates());
72         }
73
74         @Override
75         public final boolean equals(@Nullable final Object obj) {
76             if (this == obj) {
77                 return true;
78             }
79             if (!(obj instanceof AxisStep)) {
80                 return false;
81             }
82             final AxisStep other = (AxisStep) obj;
83             return getAxis().equals(other.getAxis()) && getPredicates().equals(other.getPredicates());
84         }
85
86         private Object readResolve() {
87             return getAxis().asStep();
88         }
89     }
90
91     static final class AxisStepWithPredicates extends AxisStep {
92         private static final long serialVersionUID = 1L;
93
94         private final Set<YangExpr> predicates;
95
96         AxisStepWithPredicates(final YangXPathAxis axis, final Set<YangExpr> predicates) {
97             super(axis);
98             this.predicates = requireNonNull(predicates);
99         }
100
101         @Override
102         public Set<YangExpr> getPredicates() {
103             return predicates;
104         }
105     }
106
107     // match a particular namespace
108     public static class NamespaceStep extends Step {
109         private static final long serialVersionUID = 1L;
110
111         private final QNameModule namespace;
112
113         NamespaceStep(final YangXPathAxis axis, final QNameModule namespace) {
114             super(axis);
115             this.namespace = requireNonNull(namespace);
116         }
117
118         public final QNameModule getNamespace() {
119             return namespace;
120         }
121
122         @Override
123         public final int hashCode() {
124             return Objects.hash(getAxis(), namespace, getPredicates());
125         }
126
127         @Override
128         public final boolean equals(@Nullable final Object obj) {
129             if (this == obj) {
130                 return true;
131             }
132             if (!(obj instanceof NamespaceStep)) {
133                 return false;
134             }
135             final NamespaceStep other = (NamespaceStep) obj;
136             return getAxis().equals(other.getAxis()) && namespace.equals(other.namespace)
137                     && getPredicates().equals(other.getPredicates());
138         }
139
140         @Override
141         protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
142             return super.addToStringAttributes(helper).add("namespace", namespace);
143         }
144     }
145
146     public static class QNameStep extends Step {
147         private static final long serialVersionUID = 1L;
148
149         private final QName qname;
150
151         QNameStep(final YangXPathAxis axis, final QName qname) {
152             super(axis);
153             this.qname = requireNonNull(qname);
154         }
155
156         public final QName getQName() {
157             return qname;
158         }
159
160         @Override
161         public final int hashCode() {
162             return Objects.hash(getAxis(), qname, getPredicates());
163         }
164
165         @Override
166         public final boolean equals(@Nullable final Object obj) {
167             if (this == obj) {
168                 return true;
169             }
170             if (!(obj instanceof QNameStep)) {
171                 return false;
172             }
173             final QNameStep other = (QNameStep) obj;
174             return getAxis().equals(other.getAxis()) && qname.equals(other.qname)
175                     && getPredicates().equals(other.getPredicates());
176         }
177
178         @Override
179         protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
180             return super.addToStringAttributes(helper).add("qname", qname);
181         }
182     }
183
184     static final class QNameStepWithPredicates extends QNameStep {
185         private static final long serialVersionUID = 1L;
186
187         private final Set<YangExpr> predicates;
188
189         QNameStepWithPredicates(final YangXPathAxis axis, final QName qname, final Set<YangExpr> predicates) {
190             super(axis, qname);
191             this.predicates = requireNonNull(predicates);
192         }
193
194         @Override
195         public Set<YangExpr> getPredicates() {
196             return predicates;
197         }
198     }
199
200     public static class NodeTypeStep extends Step {
201         private static final long serialVersionUID = 1L;
202
203         private final YangXPathNodeType nodeType;
204
205         NodeTypeStep(final YangXPathAxis axis, final YangXPathNodeType nodeType) {
206             super(axis);
207             this.nodeType = requireNonNull(nodeType);
208         }
209
210         public final YangXPathNodeType getNodeType() {
211             return nodeType;
212         }
213
214         @Override
215         public int hashCode() {
216             return Objects.hash(getAxis(), nodeType, getPredicates());
217         }
218
219         @Override
220         public boolean equals(@Nullable final Object obj) {
221             if (this == obj) {
222                 return true;
223             }
224             if (obj == null || !getClass().equals(obj.getClass())) {
225                 return false;
226             }
227             final NodeTypeStep other = (NodeTypeStep) obj;
228             return nodeType.equals(other.nodeType) && getAxis().equals(other.getAxis())
229                     && getPredicates().equals(other.getPredicates());
230         }
231
232         @Override
233         protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
234             return super.addToStringAttributes(helper).add("nodeType", nodeType);
235         }
236     }
237
238     static final class NodeTypeStepWithPredicates extends NodeTypeStep {
239         private static final long serialVersionUID = 1L;
240
241         private final Set<YangExpr> predicates;
242
243         NodeTypeStepWithPredicates(final YangXPathAxis axis, final YangXPathNodeType type,
244                 final Set<YangExpr> predicates) {
245             super(axis, type);
246             this.predicates = requireNonNull(predicates);
247         }
248
249         @Override
250         public Set<YangExpr> getPredicates() {
251             return predicates;
252         }
253     }
254
255     public static class ProcessingInstructionStep extends NodeTypeStep {
256         private static final long serialVersionUID = 1L;
257
258         private final String name;
259
260         ProcessingInstructionStep(final YangXPathAxis axis, final String name) {
261             super(axis, YangXPathNodeType.PROCESSING_INSTRUCTION);
262             this.name = requireNonNull(name);
263         }
264
265         public final String getName() {
266             return name;
267         }
268
269         @Override
270         public final int hashCode() {
271             return Objects.hash(getAxis(), getNodeType(), name, getPredicates());
272         }
273
274         @Override
275         public final boolean equals(final @Nullable Object obj) {
276             return obj == this || super.equals(obj) && name.equals(((ProcessingInstructionStep) obj).name);
277         }
278
279         @Override
280         protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
281             return super.addToStringAttributes(helper).add("name", name);
282         }
283     }
284
285     static final class ProcessingInstructionStepWithPredicates extends ProcessingInstructionStep {
286         private static final long serialVersionUID = 1L;
287
288         private final Set<YangExpr> predicates;
289
290         ProcessingInstructionStepWithPredicates(final YangXPathAxis axis, final String name,
291                 final Set<YangExpr> predicates) {
292             super(axis, name);
293             this.predicates = requireNonNull(predicates);
294         }
295
296         @Override
297         public Set<YangExpr> getPredicates() {
298             return predicates;
299         }
300     }
301
302     public static class Absolute extends YangLocationPath {
303         private static final long serialVersionUID = 1L;
304
305         @Override
306         public final boolean isAbsolute() {
307             return true;
308         }
309     }
310
311     private static final class AbsoluteWithSteps extends Absolute {
312         private static final long serialVersionUID = 1L;
313
314         private final List<Step> steps;
315
316         AbsoluteWithSteps(final List<Step> steps) {
317             this.steps = requireNonNull(steps);
318         }
319
320         @Override
321         public List<Step> getSteps() {
322             return steps;
323         }
324     }
325
326     private static final class WithSteps extends YangLocationPath {
327         private static final long serialVersionUID = 1L;
328
329         private final List<Step> steps;
330
331         WithSteps(final List<Step> steps) {
332             this.steps = requireNonNull(steps);
333         }
334
335         @Override
336         public List<Step> getSteps() {
337             return steps;
338         }
339     }
340
341     private static final long serialVersionUID = 1L;
342     private static final YangLocationPath ROOT = new Absolute();
343     private static final YangLocationPath SELF = new YangLocationPath();
344
345     YangLocationPath() {
346         // Hidden to prevent external instantiation
347     }
348
349     public static final YangLocationPath of(final boolean absolute) {
350         return absolute ? ROOT : SELF;
351     }
352
353     public static final YangLocationPath of(final boolean absolute, final Step... steps) {
354         return of(absolute, Arrays.asList(steps));
355     }
356
357     public static final YangLocationPath of(final boolean absolute, final Collection<Step> steps) {
358         if (steps.isEmpty()) {
359             return of(absolute);
360         }
361
362         final List<Step> copy = ImmutableList.copyOf(steps);
363         return absolute ? new AbsoluteWithSteps(copy) : new WithSteps(copy);
364     }
365
366     /**
367      * The conceptual {@code root} {@link YangLocationPath}. This path is an absolute path and has no steps.
368      *
369      * @return Empty absolute {@link YangLocationPath}
370      */
371     public static final YangLocationPath root() {
372         return ROOT;
373     }
374
375     /**
376      * The conceptual {@code same} {@link YangLocationPath}. This path is a relative path and has no steps and is
377      * equivalent to a step along {@link YangXPathAxis#SELF}.
378      *
379      * @return Empty relative {@link YangLocationPath}
380      */
381     public static YangLocationPath self() {
382         return SELF;
383     }
384
385     public boolean isAbsolute() {
386         return false;
387     }
388
389     public List<Step> getSteps() {
390         return ImmutableList.of();
391     }
392
393     @Override
394     public final int hashCode() {
395         return Boolean.hashCode(isAbsolute()) * 31 + getSteps().hashCode();
396     }
397
398     @Override
399     public final boolean equals(final @Nullable Object obj) {
400         if (this == obj) {
401             return true;
402         }
403         if (!(obj instanceof YangLocationPath)) {
404             return false;
405         }
406         final YangLocationPath other = (YangLocationPath) obj;
407         return isAbsolute() == other.isAbsolute() && getSteps().equals(other.getSteps());
408     }
409 }