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.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;
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;
35 private final YangXPathAxis axis;
37 Step(final YangXPathAxis axis) {
38 this.axis = requireNonNull(axis);
41 public final YangXPathAxis getAxis() {
46 public abstract int hashCode();
49 public abstract boolean equals(@Nullable Object obj);
52 public final String toString() {
53 return addToStringAttributes(MoreObjects.toStringHelper(Step.class)).toString();
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);
66 public static sealed class AxisStep extends Step {
67 private static final long serialVersionUID = 1L;
69 AxisStep(final YangXPathAxis axis) {
74 public final int hashCode() {
75 return Objects.hash(getAxis(), getPredicates());
79 public final boolean equals(@Nullable final Object obj) {
83 if (!(obj instanceof AxisStep)) {
86 final AxisStep other = (AxisStep) obj;
87 return getAxis().equals(other.getAxis()) && getPredicates().equals(other.getPredicates());
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();
97 static final class AxisStepWithPredicates extends AxisStep {
98 private static final long serialVersionUID = 1L;
100 private final ImmutableSet<YangExpr> predicates;
102 AxisStepWithPredicates(final YangXPathAxis axis, final ImmutableSet<YangExpr> predicates) {
104 this.predicates = requireNonNull(predicates);
108 public ImmutableSet<YangExpr> getPredicates() {
113 // match a particular namespace
114 public static final class NamespaceStep extends Step {
115 private static final long serialVersionUID = 1L;
117 private final QNameModule namespace;
119 NamespaceStep(final YangXPathAxis axis, final QNameModule namespace) {
121 this.namespace = requireNonNull(namespace);
124 public QNameModule getNamespace() {
129 public int hashCode() {
130 return Objects.hash(getAxis(), namespace, getPredicates());
134 public boolean equals(@Nullable final Object obj) {
138 if (!(obj instanceof NamespaceStep)) {
141 final NamespaceStep other = (NamespaceStep) obj;
142 return getAxis().equals(other.getAxis()) && namespace.equals(other.namespace)
143 && getPredicates().equals(other.getPredicates());
147 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
148 return super.addToStringAttributes(helper).add("namespace", namespace);
153 * A step along an axis. This may be either a {@link ResolvedQNameStep} or a {@link UnresolvedQNameStep}.
155 * @author Robert Varga
157 public abstract static sealed class QNameStep extends Step implements QNameReferent {
158 private static final long serialVersionUID = 1L;
160 QNameStep(final YangXPathAxis axis) {
165 private abstract static sealed class AbstractQNameStep<T extends AbstractQName> extends QNameStep {
166 private static final long serialVersionUID = 1L;
168 private final T qname;
170 AbstractQNameStep(final YangXPathAxis axis, final T qname) {
172 this.qname = requireNonNull(qname);
176 public final @NonNull T getQName() {
181 public final int hashCode() {
182 return Objects.hash(getAxis(), qname, getPredicates());
186 @SuppressFBWarnings(value = "EQ_UNUSUAL", justification = "Polymorphic via equalityClass()")
187 public final boolean equals(final @Nullable Object obj) {
191 final Class<? extends AbstractQNameStep<?>> eq = equalityClass();
192 if (!equalityClass().isInstance(obj)) {
196 final AbstractQNameStep<?> other = eq.cast(obj);
197 return getAxis().equals(other.getAxis()) && qname.equals(other.qname)
198 && getPredicates().equals(other.getPredicates());
202 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
203 return super.addToStringAttributes(helper).add("qname", qname);
206 abstract Class<? extends AbstractQNameStep<?>> equalityClass();
209 public static sealed class ResolvedQNameStep extends AbstractQNameStep<QName> implements ResolvedQNameReferent {
210 private static final long serialVersionUID = 1L;
212 ResolvedQNameStep(final YangXPathAxis axis, final QName qname) {
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));
223 final Class<ResolvedQNameStep> equalityClass() {
224 return ResolvedQNameStep.class;
228 private static final class ResolvedQNameStepWithPredicates extends ResolvedQNameStep {
229 private static final long serialVersionUID = 1L;
231 private final ImmutableSet<YangExpr> predicates;
233 ResolvedQNameStepWithPredicates(final YangXPathAxis axis, final QName qname,
234 final ImmutableSet<YangExpr> predicates) {
236 this.predicates = requireNonNull(predicates);
240 public ImmutableSet<YangExpr> getPredicates() {
245 public static sealed class UnresolvedQNameStep extends AbstractQNameStep<UnresolvedQName>
246 implements UnresolvedQNameReferent {
247 private static final long serialVersionUID = 1L;
249 UnresolvedQNameStep(final YangXPathAxis axis, final UnresolvedQName qname) {
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));
260 final Class<UnresolvedQNameStep> equalityClass() {
261 return UnresolvedQNameStep.class;
265 private static final class UnresolvedQNameStepWithPredicates extends UnresolvedQNameStep {
266 private static final long serialVersionUID = 1L;
268 private final ImmutableSet<YangExpr> predicates;
270 UnresolvedQNameStepWithPredicates(final YangXPathAxis axis, final UnresolvedQName qname,
271 final ImmutableSet<YangExpr> predicates) {
273 this.predicates = requireNonNull(predicates);
277 public ImmutableSet<YangExpr> getPredicates() {
282 public static sealed class NodeTypeStep extends Step {
283 private static final long serialVersionUID = 1L;
285 private final YangXPathNodeType nodeType;
287 NodeTypeStep(final YangXPathAxis axis, final YangXPathNodeType nodeType) {
289 this.nodeType = requireNonNull(nodeType);
292 public final YangXPathNodeType getNodeType() {
297 public int hashCode() {
298 return Objects.hash(getAxis(), nodeType, getPredicates());
302 public boolean equals(@Nullable final Object obj) {
306 if (obj == null || !getClass().equals(obj.getClass())) {
309 final NodeTypeStep other = (NodeTypeStep) obj;
310 return nodeType.equals(other.nodeType) && getAxis().equals(other.getAxis())
311 && getPredicates().equals(other.getPredicates());
315 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
316 return super.addToStringAttributes(helper).add("nodeType", nodeType);
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;
325 private final ImmutableSet<YangExpr> predicates;
327 NodeTypeStepWithPredicates(final YangXPathAxis axis, final YangXPathNodeType type,
328 final ImmutableSet<YangExpr> predicates) {
330 this.predicates = requireNonNull(predicates);
334 public ImmutableSet<YangExpr> getPredicates() {
339 public static sealed class ProcessingInstructionStep extends NodeTypeStep {
340 private static final long serialVersionUID = 1L;
342 private final String name;
344 ProcessingInstructionStep(final YangXPathAxis axis, final String name) {
345 super(axis, YangXPathNodeType.PROCESSING_INSTRUCTION);
346 this.name = requireNonNull(name);
349 public final String getName() {
354 public final int hashCode() {
355 return Objects.hash(getAxis(), getNodeType(), name, getPredicates());
359 public final boolean equals(final @Nullable Object obj) {
360 return obj == this || super.equals(obj) && name.equals(((ProcessingInstructionStep) obj).name);
364 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
365 return super.addToStringAttributes(helper).add("name", name);
369 static final class ProcessingInstructionStepWithPredicates extends ProcessingInstructionStep {
370 private static final long serialVersionUID = 1L;
372 private final ImmutableSet<YangExpr> predicates;
374 ProcessingInstructionStepWithPredicates(final YangXPathAxis axis, final String name,
375 final ImmutableSet<YangExpr> predicates) {
377 this.predicates = requireNonNull(predicates);
381 public ImmutableSet<YangExpr> getPredicates() {
386 public static final class Absolute extends YangLocationPath {
387 private static final long serialVersionUID = 1L;
389 Absolute(final ImmutableList<Step> steps) {
394 public boolean isAbsolute() {
399 public static final class Relative extends YangLocationPath {
400 private static final long serialVersionUID = 1L;
402 Relative(final ImmutableList<Step> steps) {
407 public boolean isAbsolute() {
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());
416 private final ImmutableList<Step> steps;
418 private YangLocationPath(final ImmutableList<Step> steps) {
419 this.steps = requireNonNull(steps);
422 public static final Absolute absolute(final Step... steps) {
423 return absolute(Arrays.asList(steps));
426 public static final Absolute absolute(final Collection<Step> steps) {
427 return steps.isEmpty() ? ROOT : new Absolute(ImmutableList.copyOf(steps));
430 public static final Relative relative(final Step... steps) {
431 return relative(Arrays.asList(steps));
434 public static final Relative relative(final Collection<Step> steps) {
435 return steps.isEmpty() ? SELF : new Relative(ImmutableList.copyOf(steps));
439 * The conceptual {@code root} {@link YangLocationPath}. This path is an absolute path and has no steps.
441 * @return Empty absolute {@link YangLocationPath}
443 public static final Absolute root() {
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}.
451 * @return Empty relative {@link YangLocationPath}
453 public static final Relative self() {
457 public final ImmutableList<Step> getSteps() {
461 public abstract boolean isAbsolute();
464 public final int hashCode() {
465 return Boolean.hashCode(isAbsolute()) * 31 + steps.hashCode();
469 public final boolean equals(final @Nullable Object obj) {
473 if (!(obj instanceof YangLocationPath)) {
476 final YangLocationPath other = (YangLocationPath) obj;
477 return isAbsolute() == other.isAbsolute() && steps.equals(other.steps);
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);
486 return helper.toString();
489 final Object readSolve() {
490 return steps.isEmpty() ? isAbsolute() ? ROOT : SELF : this;