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