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