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