2 * Copyright (c) 2018 Pantheon Technologies, s.r.o. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.xpath.api;
10 import static java.util.Objects.requireNonNull;
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;
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;
29 public abstract class YangLocationPath implements YangExpr {
30 public abstract static class Step implements Serializable, YangPredicateAware {
31 private static final long serialVersionUID = 1L;
33 private final YangXPathAxis axis;
35 Step(final YangXPathAxis axis) {
36 this.axis = requireNonNull(axis);
39 public final YangXPathAxis getAxis() {
44 public abstract int hashCode();
47 public abstract boolean equals(@Nullable Object obj);
50 public final String toString() {
51 return addToStringAttributes(MoreObjects.toStringHelper(Step.class)).toString();
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);
64 public static class AxisStep extends Step {
65 private static final long serialVersionUID = 1L;
67 AxisStep(final YangXPathAxis axis) {
72 public final int hashCode() {
73 return Objects.hash(getAxis(), getPredicates());
77 public final boolean equals(@Nullable final Object obj) {
81 if (!(obj instanceof AxisStep)) {
84 final AxisStep other = (AxisStep) obj;
85 return getAxis().equals(other.getAxis()) && getPredicates().equals(other.getPredicates());
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();
95 static final class AxisStepWithPredicates extends AxisStep {
96 private static final long serialVersionUID = 1L;
98 private final ImmutableSet<YangExpr> predicates;
100 AxisStepWithPredicates(final YangXPathAxis axis, final ImmutableSet<YangExpr> predicates) {
102 this.predicates = requireNonNull(predicates);
106 public ImmutableSet<YangExpr> getPredicates() {
111 // match a particular namespace
112 public static class NamespaceStep extends Step {
113 private static final long serialVersionUID = 1L;
115 private final QNameModule namespace;
117 NamespaceStep(final YangXPathAxis axis, final QNameModule namespace) {
119 this.namespace = requireNonNull(namespace);
122 public final QNameModule getNamespace() {
127 public final int hashCode() {
128 return Objects.hash(getAxis(), namespace, getPredicates());
132 public final boolean equals(@Nullable final Object obj) {
136 if (!(obj instanceof NamespaceStep)) {
139 final NamespaceStep other = (NamespaceStep) obj;
140 return getAxis().equals(other.getAxis()) && namespace.equals(other.namespace)
141 && getPredicates().equals(other.getPredicates());
145 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
146 return super.addToStringAttributes(helper).add("namespace", namespace);
151 * A step along an axis. This may be either a {@link ResolvedQNameStep} or a {@link UnresolvedQNameStep}.
153 * @author Robert Varga
155 public abstract static class QNameStep extends Step implements QNameReferent {
156 private static final long serialVersionUID = 1L;
158 QNameStep(final YangXPathAxis axis) {
163 public static class ResolvedQNameStep extends QNameStep implements ResolvedQNameReferent {
164 private static final long serialVersionUID = 1L;
166 private final QName qname;
168 ResolvedQNameStep(final YangXPathAxis axis, final QName qname) {
170 this.qname = requireNonNull(qname);
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));
180 public final QName getQName() {
185 public final int hashCode() {
186 return Objects.hash(getAxis(), qname, getPredicates());
190 public final boolean equals(@Nullable final Object obj) {
194 if (!(obj instanceof ResolvedQNameStep)) {
197 final ResolvedQNameStep other = (ResolvedQNameStep) obj;
198 return getAxis().equals(other.getAxis()) && qname.equals(other.qname)
199 && getPredicates().equals(other.getPredicates());
203 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
204 return super.addToStringAttributes(helper).add("qname", qname);
208 private static final class ResolvedQNameStepWithPredicates extends ResolvedQNameStep {
209 private static final long serialVersionUID = 1L;
211 private final ImmutableSet<YangExpr> predicates;
213 ResolvedQNameStepWithPredicates(final YangXPathAxis axis, final QName qname,
214 final ImmutableSet<YangExpr> predicates) {
216 this.predicates = requireNonNull(predicates);
220 public ImmutableSet<YangExpr> getPredicates() {
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;
229 private final AbstractQName qname;
231 UnresolvedQNameStep(final YangXPathAxis axis, final AbstractQName qname) {
233 this.qname = requireNonNull(qname);
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));
243 public final AbstractQName getQName() {
248 public final int hashCode() {
249 return Objects.hash(getAxis(), qname, getPredicates());
253 public final boolean equals(final @Nullable Object obj) {
257 if (!(obj instanceof UnresolvedQNameStep)) {
260 final UnresolvedQNameStep other = (UnresolvedQNameStep) obj;
261 return getAxis().equals(other.getAxis()) && qname.equals(other.qname)
262 && getPredicates().equals(other.getPredicates());
266 private static final class UnresolvedQNameStepWithPredicates extends UnresolvedQNameStep {
267 private static final long serialVersionUID = 1L;
269 private final ImmutableSet<YangExpr> predicates;
271 UnresolvedQNameStepWithPredicates(final YangXPathAxis axis, final AbstractQName qname,
272 final ImmutableSet<YangExpr> predicates) {
274 this.predicates = requireNonNull(predicates);
278 public ImmutableSet<YangExpr> getPredicates() {
283 public static class NodeTypeStep extends Step {
284 private static final long serialVersionUID = 1L;
286 private final YangXPathNodeType nodeType;
288 NodeTypeStep(final YangXPathAxis axis, final YangXPathNodeType nodeType) {
290 this.nodeType = requireNonNull(nodeType);
293 public final YangXPathNodeType getNodeType() {
298 public int hashCode() {
299 return Objects.hash(getAxis(), nodeType, getPredicates());
303 public boolean equals(@Nullable final Object obj) {
307 if (obj == null || !getClass().equals(obj.getClass())) {
310 final NodeTypeStep other = (NodeTypeStep) obj;
311 return nodeType.equals(other.nodeType) && getAxis().equals(other.getAxis())
312 && getPredicates().equals(other.getPredicates());
316 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
317 return super.addToStringAttributes(helper).add("nodeType", nodeType);
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;
326 private final ImmutableSet<YangExpr> predicates;
328 NodeTypeStepWithPredicates(final YangXPathAxis axis, final YangXPathNodeType type,
329 final ImmutableSet<YangExpr> predicates) {
331 this.predicates = requireNonNull(predicates);
335 public ImmutableSet<YangExpr> getPredicates() {
340 public static class ProcessingInstructionStep extends NodeTypeStep {
341 private static final long serialVersionUID = 1L;
343 private final String name;
345 ProcessingInstructionStep(final YangXPathAxis axis, final String name) {
346 super(axis, YangXPathNodeType.PROCESSING_INSTRUCTION);
347 this.name = requireNonNull(name);
350 public final String getName() {
355 public final int hashCode() {
356 return Objects.hash(getAxis(), getNodeType(), name, getPredicates());
360 public final boolean equals(final @Nullable Object obj) {
361 return obj == this || super.equals(obj) && name.equals(((ProcessingInstructionStep) obj).name);
365 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
366 return super.addToStringAttributes(helper).add("name", name);
370 static final class ProcessingInstructionStepWithPredicates extends ProcessingInstructionStep {
371 private static final long serialVersionUID = 1L;
373 private final ImmutableSet<YangExpr> predicates;
375 ProcessingInstructionStepWithPredicates(final YangXPathAxis axis, final String name,
376 final ImmutableSet<YangExpr> predicates) {
378 this.predicates = requireNonNull(predicates);
382 public ImmutableSet<YangExpr> getPredicates() {
387 public static final class Absolute extends YangLocationPath {
388 private static final long serialVersionUID = 1L;
390 Absolute(final ImmutableList<Step> steps) {
395 public boolean isAbsolute() {
400 public static final class Relative extends YangLocationPath {
401 private static final long serialVersionUID = 1L;
403 Relative(final ImmutableList<Step> steps) {
408 public boolean isAbsolute() {
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());
417 private final ImmutableList<Step> steps;
419 YangLocationPath(final ImmutableList<Step> steps) {
420 this.steps = requireNonNull(steps);
423 public static final Absolute absolute(final Step... steps) {
424 return absolute(Arrays.asList(steps));
427 public static final Absolute absolute(final Collection<Step> steps) {
428 return steps.isEmpty() ? ROOT : new Absolute(ImmutableList.copyOf(steps));
431 public static final Relative relative(final Step... steps) {
432 return relative(Arrays.asList(steps));
435 public static final Relative relative(final Collection<Step> steps) {
436 return steps.isEmpty() ? SELF : new Relative(ImmutableList.copyOf(steps));
440 * The conceptual {@code root} {@link YangLocationPath}. This path is an absolute path and has no steps.
442 * @return Empty absolute {@link YangLocationPath}
444 public static final Absolute root() {
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}.
452 * @return Empty relative {@link YangLocationPath}
454 public static final Relative self() {
458 public final ImmutableList<Step> getSteps() {
462 public abstract boolean isAbsolute();
465 public final int hashCode() {
466 return Boolean.hashCode(isAbsolute()) * 31 + steps.hashCode();
470 public final boolean equals(final @Nullable Object obj) {
474 if (!(obj instanceof YangLocationPath)) {
477 final YangLocationPath other = (YangLocationPath) obj;
478 return isAbsolute() == other.isAbsolute() && steps.equals(other.steps);
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);
487 return helper.toString();
490 final Object readSolve() {
491 return steps.isEmpty() ? isAbsolute() ? ROOT : SELF : this;