Populate xpath/ hierarchy
[yangtools.git] / xpath / 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 com.google.common.collect.ImmutableSet;
17 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
18 import java.io.Serializable;
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.Objects;
22 import java.util.Set;
23 import org.eclipse.jdt.annotation.NonNull;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.opendaylight.yangtools.yang.common.AbstractQName;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.common.QNameModule;
28
29 @Beta
30 public abstract class YangLocationPath implements YangExpr {
31     public abstract static class Step implements Serializable, YangPredicateAware {
32         private static final long serialVersionUID = 1L;
33
34         private final YangXPathAxis axis;
35
36         Step(final YangXPathAxis axis) {
37             this.axis = requireNonNull(axis);
38         }
39
40         public final YangXPathAxis getAxis() {
41             return axis;
42         }
43
44         @Override
45         public abstract int hashCode();
46
47         @Override
48         public abstract boolean equals(@Nullable Object obj);
49
50         @Override
51         public final String toString() {
52             return addToStringAttributes(MoreObjects.toStringHelper(Step.class)).toString();
53         }
54
55         protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
56             helper.add("axis", axis);
57             final Set<YangExpr> predicates = getPredicates();
58             if (!predicates.isEmpty()) {
59                 helper.add("predicates", predicates);
60             }
61             return helper;
62         }
63     }
64
65     public static class AxisStep extends Step {
66         private static final long serialVersionUID = 1L;
67
68         AxisStep(final YangXPathAxis axis) {
69             super(axis);
70         }
71
72         @Override
73         public final int hashCode() {
74             return Objects.hash(getAxis(), getPredicates());
75         }
76
77         @Override
78         public final boolean equals(@Nullable final Object obj) {
79             if (this == obj) {
80                 return true;
81             }
82             if (!(obj instanceof AxisStep)) {
83                 return false;
84             }
85             final AxisStep other = (AxisStep) obj;
86             return getAxis().equals(other.getAxis()) && getPredicates().equals(other.getPredicates());
87         }
88
89         @SuppressFBWarnings(value = "SE_PRIVATE_READ_RESOLVE_NOT_INHERITED",
90                 justification = "We have only one subclass, and that does not want to inherit this")
91         private Object readResolve() {
92             return getAxis().asStep();
93         }
94     }
95
96     static final class AxisStepWithPredicates extends AxisStep {
97         private static final long serialVersionUID = 1L;
98
99         private final ImmutableSet<YangExpr> predicates;
100
101         AxisStepWithPredicates(final YangXPathAxis axis, final ImmutableSet<YangExpr> predicates) {
102             super(axis);
103             this.predicates = requireNonNull(predicates);
104         }
105
106         @Override
107         public ImmutableSet<YangExpr> getPredicates() {
108             return predicates;
109         }
110     }
111
112     // match a particular namespace
113     public static class NamespaceStep extends Step {
114         private static final long serialVersionUID = 1L;
115
116         private final QNameModule namespace;
117
118         NamespaceStep(final YangXPathAxis axis, final QNameModule namespace) {
119             super(axis);
120             this.namespace = requireNonNull(namespace);
121         }
122
123         public final QNameModule getNamespace() {
124             return namespace;
125         }
126
127         @Override
128         public final int hashCode() {
129             return Objects.hash(getAxis(), namespace, getPredicates());
130         }
131
132         @Override
133         public final boolean equals(@Nullable final Object obj) {
134             if (this == obj) {
135                 return true;
136             }
137             if (!(obj instanceof NamespaceStep)) {
138                 return false;
139             }
140             final NamespaceStep other = (NamespaceStep) obj;
141             return getAxis().equals(other.getAxis()) && namespace.equals(other.namespace)
142                     && getPredicates().equals(other.getPredicates());
143         }
144
145         @Override
146         protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
147             return super.addToStringAttributes(helper).add("namespace", namespace);
148         }
149     }
150
151     /**
152      * A step along an axis. This may be either a {@link ResolvedQNameStep} or a {@link UnresolvedQNameStep}.
153      *
154      * @author Robert Varga
155      */
156     public abstract static class QNameStep extends Step implements QNameReferent {
157         private static final long serialVersionUID = 1L;
158
159         QNameStep(final YangXPathAxis axis) {
160             super(axis);
161         }
162     }
163
164     private abstract static class AbstractQNameStep<T extends AbstractQName> extends QNameStep {
165         private static final long serialVersionUID = 1L;
166
167         private final T qname;
168
169         AbstractQNameStep(final YangXPathAxis axis, final T qname) {
170             super(axis);
171             this.qname = requireNonNull(qname);
172         }
173
174         @Override
175         public final @NonNull T getQName() {
176             return qname;
177         }
178
179         @Override
180         public final int hashCode() {
181             return Objects.hash(getAxis(), qname, getPredicates());
182         }
183
184         @Override
185         @SuppressFBWarnings(value = "EQ_UNUSUAL", justification = "Polymorphic via equalityClass()")
186         public final boolean equals(final @Nullable Object obj) {
187             if (this == obj) {
188                 return true;
189             }
190             final Class<? extends AbstractQNameStep<?>> eq = equalityClass();
191             if (!equalityClass().isInstance(obj)) {
192                 return false;
193             }
194
195             final AbstractQNameStep<?> other = eq.cast(obj);
196             return getAxis().equals(other.getAxis()) && qname.equals(other.qname)
197                     && getPredicates().equals(other.getPredicates());
198         }
199
200         @Override
201         protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
202             return super.addToStringAttributes(helper).add("qname", qname);
203         }
204
205         abstract Class<? extends AbstractQNameStep<?>> equalityClass();
206     }
207
208     public static class ResolvedQNameStep extends AbstractQNameStep<QName> implements ResolvedQNameReferent {
209         private static final long serialVersionUID = 1L;
210
211         ResolvedQNameStep(final YangXPathAxis axis, final QName qname) {
212             super(axis, qname);
213         }
214
215         static ResolvedQNameStep of(final YangXPathAxis axis, final QName qname,
216                 final Collection<YangExpr> predicates) {
217             return predicates.isEmpty() ? new ResolvedQNameStep(axis, qname)
218                     : new ResolvedQNameStepWithPredicates(axis, qname, ImmutableSet.copyOf(predicates));
219         }
220
221         @Override
222         final Class<ResolvedQNameStep> equalityClass() {
223             return ResolvedQNameStep.class;
224         }
225     }
226
227     private static final class ResolvedQNameStepWithPredicates extends ResolvedQNameStep {
228         private static final long serialVersionUID = 1L;
229
230         private final ImmutableSet<YangExpr> predicates;
231
232         ResolvedQNameStepWithPredicates(final YangXPathAxis axis, final QName qname,
233                 final ImmutableSet<YangExpr> predicates) {
234             super(axis, qname);
235             this.predicates = requireNonNull(predicates);
236         }
237
238         @Override
239         public ImmutableSet<YangExpr> getPredicates() {
240             return predicates;
241         }
242     }
243
244     public static class UnresolvedQNameStep extends AbstractQNameStep<AbstractQName>
245             implements UnresolvedQNameReferent<ResolvedQNameStep> {
246         private static final long serialVersionUID = 1L;
247
248         UnresolvedQNameStep(final YangXPathAxis axis, final AbstractQName qname) {
249             super(axis, qname);
250         }
251
252         static UnresolvedQNameStep of(final YangXPathAxis axis, final AbstractQName qname,
253                 final Collection<YangExpr> predicates) {
254             return predicates.isEmpty() ? new UnresolvedQNameStep(axis, qname)
255                     : new UnresolvedQNameStepWithPredicates(axis, qname, ImmutableSet.copyOf(predicates));
256         }
257
258         @Override
259         final Class<UnresolvedQNameStep> equalityClass() {
260             return UnresolvedQNameStep.class;
261         }
262     }
263
264     private static final class UnresolvedQNameStepWithPredicates extends UnresolvedQNameStep {
265         private static final long serialVersionUID = 1L;
266
267         private final ImmutableSet<YangExpr> predicates;
268
269         UnresolvedQNameStepWithPredicates(final YangXPathAxis axis, final AbstractQName qname,
270                 final ImmutableSet<YangExpr> predicates) {
271             super(axis, qname);
272             this.predicates = requireNonNull(predicates);
273         }
274
275         @Override
276         public ImmutableSet<YangExpr> getPredicates() {
277             return predicates;
278         }
279     }
280
281     public static class NodeTypeStep extends Step {
282         private static final long serialVersionUID = 1L;
283
284         private final YangXPathNodeType nodeType;
285
286         NodeTypeStep(final YangXPathAxis axis, final YangXPathNodeType nodeType) {
287             super(axis);
288             this.nodeType = requireNonNull(nodeType);
289         }
290
291         public final YangXPathNodeType getNodeType() {
292             return nodeType;
293         }
294
295         @Override
296         public int hashCode() {
297             return Objects.hash(getAxis(), nodeType, getPredicates());
298         }
299
300         @Override
301         public boolean equals(@Nullable final Object obj) {
302             if (this == obj) {
303                 return true;
304             }
305             if (obj == null || !getClass().equals(obj.getClass())) {
306                 return false;
307             }
308             final NodeTypeStep other = (NodeTypeStep) obj;
309             return nodeType.equals(other.nodeType) && getAxis().equals(other.getAxis())
310                     && getPredicates().equals(other.getPredicates());
311         }
312
313         @Override
314         protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
315             return super.addToStringAttributes(helper).add("nodeType", nodeType);
316         }
317     }
318
319     @SuppressFBWarnings(value = "EQ_DOESNT_OVERRIDE_EQUALS",
320             justification = "https://github.com/spotbugs/spotbugs/issues/511")
321     static final class NodeTypeStepWithPredicates extends NodeTypeStep {
322         private static final long serialVersionUID = 1L;
323
324         private final ImmutableSet<YangExpr> predicates;
325
326         NodeTypeStepWithPredicates(final YangXPathAxis axis, final YangXPathNodeType type,
327                 final ImmutableSet<YangExpr> predicates) {
328             super(axis, type);
329             this.predicates = requireNonNull(predicates);
330         }
331
332         @Override
333         public ImmutableSet<YangExpr> getPredicates() {
334             return predicates;
335         }
336     }
337
338     public static class ProcessingInstructionStep extends NodeTypeStep {
339         private static final long serialVersionUID = 1L;
340
341         private final String name;
342
343         ProcessingInstructionStep(final YangXPathAxis axis, final String name) {
344             super(axis, YangXPathNodeType.PROCESSING_INSTRUCTION);
345             this.name = requireNonNull(name);
346         }
347
348         public final String getName() {
349             return name;
350         }
351
352         @Override
353         public final int hashCode() {
354             return Objects.hash(getAxis(), getNodeType(), name, getPredicates());
355         }
356
357         @Override
358         public final boolean equals(final @Nullable Object obj) {
359             return obj == this || super.equals(obj) && name.equals(((ProcessingInstructionStep) obj).name);
360         }
361
362         @Override
363         protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
364             return super.addToStringAttributes(helper).add("name", name);
365         }
366     }
367
368     static final class ProcessingInstructionStepWithPredicates extends ProcessingInstructionStep {
369         private static final long serialVersionUID = 1L;
370
371         private final ImmutableSet<YangExpr> predicates;
372
373         ProcessingInstructionStepWithPredicates(final YangXPathAxis axis, final String name,
374                 final ImmutableSet<YangExpr> predicates) {
375             super(axis, name);
376             this.predicates = requireNonNull(predicates);
377         }
378
379         @Override
380         public ImmutableSet<YangExpr> getPredicates() {
381             return predicates;
382         }
383     }
384
385     public static final class Absolute extends YangLocationPath {
386         private static final long serialVersionUID = 1L;
387
388         Absolute(final ImmutableList<Step> steps) {
389             super(steps);
390         }
391
392         @Override
393         public boolean isAbsolute() {
394             return true;
395         }
396     }
397
398     public static final class Relative extends YangLocationPath {
399         private static final long serialVersionUID = 1L;
400
401         Relative(final ImmutableList<Step> steps) {
402             super(steps);
403         }
404
405         @Override
406         public boolean isAbsolute() {
407             return false;
408         }
409     }
410
411     private static final long serialVersionUID = 1L;
412     private static final Absolute ROOT = new Absolute(ImmutableList.of());
413     private static final Relative SELF = new Relative(ImmutableList.of());
414
415     private final ImmutableList<Step> steps;
416
417     YangLocationPath(final ImmutableList<Step> steps) {
418         this.steps = requireNonNull(steps);
419     }
420
421     public static final Absolute absolute(final Step... steps) {
422         return absolute(Arrays.asList(steps));
423     }
424
425     public static final Absolute absolute(final Collection<Step> steps) {
426         return steps.isEmpty() ? ROOT : new Absolute(ImmutableList.copyOf(steps));
427     }
428
429     public static final Relative relative(final Step... steps) {
430         return relative(Arrays.asList(steps));
431     }
432
433     public static final Relative relative(final Collection<Step> steps) {
434         return steps.isEmpty() ? SELF : new Relative(ImmutableList.copyOf(steps));
435     }
436
437     /**
438      * The conceptual {@code root} {@link YangLocationPath}. This path is an absolute path and has no steps.
439      *
440      * @return Empty absolute {@link YangLocationPath}
441      */
442     public static final Absolute root() {
443         return ROOT;
444     }
445
446     /**
447      * The conceptual {@code same} {@link YangLocationPath}. This path is a relative path and has no steps and is
448      * equivalent to a step along {@link YangXPathAxis#SELF}.
449      *
450      * @return Empty relative {@link YangLocationPath}
451      */
452     public static final Relative self() {
453         return SELF;
454     }
455
456     public final ImmutableList<Step> getSteps() {
457         return steps;
458     }
459
460     public abstract boolean isAbsolute();
461
462     @Override
463     public final int hashCode() {
464         return Boolean.hashCode(isAbsolute()) * 31 + steps.hashCode();
465     }
466
467     @Override
468     public final boolean equals(final @Nullable Object obj) {
469         if (this == obj) {
470             return true;
471         }
472         if (!(obj instanceof YangLocationPath)) {
473             return false;
474         }
475         final YangLocationPath other = (YangLocationPath) obj;
476         return isAbsolute() == other.isAbsolute() && steps.equals(other.steps);
477     }
478
479     @Override
480     public final String toString() {
481         final ToStringHelper helper = MoreObjects.toStringHelper(YangLocationPath.class).add("absolute", isAbsolute());
482         if (!steps.isEmpty()) {
483             helper.add("steps", steps);
484         }
485         return helper.toString();
486     }
487
488     final Object readSolve() {
489         return steps.isEmpty() ? isAbsolute() ? ROOT : SELF : this;
490     }
491 }