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) {
80 return this == obj || obj instanceof AxisStep other && getAxis().equals(other.getAxis())
81 && getPredicates().equals(other.getPredicates());
84 @SuppressFBWarnings(value = "SE_PRIVATE_READ_RESOLVE_NOT_INHERITED",
85 justification = "We have only one subclass, and that does not want to inherit this")
86 private Object readResolve() {
87 return getAxis().asStep();
91 static final class AxisStepWithPredicates extends AxisStep {
92 private static final long serialVersionUID = 1L;
94 private final ImmutableSet<YangExpr> predicates;
96 AxisStepWithPredicates(final YangXPathAxis axis, final ImmutableSet<YangExpr> predicates) {
98 this.predicates = requireNonNull(predicates);
102 public ImmutableSet<YangExpr> getPredicates() {
107 // match a particular namespace
108 public static final class NamespaceStep extends Step {
109 private static final long serialVersionUID = 1L;
111 private final QNameModule namespace;
113 NamespaceStep(final YangXPathAxis axis, final QNameModule namespace) {
115 this.namespace = requireNonNull(namespace);
118 public QNameModule getNamespace() {
123 public int hashCode() {
124 return Objects.hash(getAxis(), namespace, getPredicates());
128 public boolean equals(@Nullable final Object obj) {
129 return this == obj || obj instanceof NamespaceStep other && getAxis().equals(other.getAxis())
130 && namespace.equals(other.namespace) && getPredicates().equals(other.getPredicates());
134 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
135 return super.addToStringAttributes(helper).add("namespace", namespace);
140 * A step along an axis. This may be either a {@link ResolvedQNameStep} or a {@link UnresolvedQNameStep}.
142 * @author Robert Varga
144 public abstract static sealed class QNameStep extends Step implements QNameReferent {
145 private static final long serialVersionUID = 1L;
147 QNameStep(final YangXPathAxis axis) {
152 private abstract static sealed class AbstractQNameStep<T extends AbstractQName> extends QNameStep {
153 private static final long serialVersionUID = 1L;
155 private final T qname;
157 AbstractQNameStep(final YangXPathAxis axis, final T qname) {
159 this.qname = requireNonNull(qname);
163 public final @NonNull T getQName() {
168 public final int hashCode() {
169 return Objects.hash(getAxis(), qname, getPredicates());
173 @SuppressFBWarnings(value = "EQ_UNUSUAL", justification = "Polymorphic via equalityClass()")
174 public final boolean equals(final @Nullable Object obj) {
178 final Class<? extends AbstractQNameStep<?>> eq = equalityClass();
179 if (!equalityClass().isInstance(obj)) {
183 final AbstractQNameStep<?> other = eq.cast(obj);
184 return getAxis().equals(other.getAxis()) && qname.equals(other.qname)
185 && getPredicates().equals(other.getPredicates());
189 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
190 return super.addToStringAttributes(helper).add("qname", qname);
193 abstract Class<? extends AbstractQNameStep<?>> equalityClass();
196 public static sealed class ResolvedQNameStep extends AbstractQNameStep<QName> implements ResolvedQNameReferent {
197 private static final long serialVersionUID = 1L;
199 ResolvedQNameStep(final YangXPathAxis axis, final QName qname) {
203 static ResolvedQNameStep of(final YangXPathAxis axis, final QName qname,
204 final Collection<YangExpr> predicates) {
205 return predicates.isEmpty() ? new ResolvedQNameStep(axis, qname)
206 : new ResolvedQNameStepWithPredicates(axis, qname, ImmutableSet.copyOf(predicates));
210 final Class<ResolvedQNameStep> equalityClass() {
211 return ResolvedQNameStep.class;
215 private static final class ResolvedQNameStepWithPredicates extends ResolvedQNameStep {
216 private static final long serialVersionUID = 1L;
218 private final ImmutableSet<YangExpr> predicates;
220 ResolvedQNameStepWithPredicates(final YangXPathAxis axis, final QName qname,
221 final ImmutableSet<YangExpr> predicates) {
223 this.predicates = requireNonNull(predicates);
227 public ImmutableSet<YangExpr> getPredicates() {
232 public static sealed class UnresolvedQNameStep extends AbstractQNameStep<UnresolvedQName>
233 implements UnresolvedQNameReferent {
234 private static final long serialVersionUID = 1L;
236 UnresolvedQNameStep(final YangXPathAxis axis, final UnresolvedQName qname) {
240 static UnresolvedQNameStep of(final YangXPathAxis axis, final UnresolvedQName qname,
241 final Collection<YangExpr> predicates) {
242 return predicates.isEmpty() ? new UnresolvedQNameStep(axis, qname)
243 : new UnresolvedQNameStepWithPredicates(axis, qname, ImmutableSet.copyOf(predicates));
247 final Class<UnresolvedQNameStep> equalityClass() {
248 return UnresolvedQNameStep.class;
252 private static final class UnresolvedQNameStepWithPredicates extends UnresolvedQNameStep {
253 private static final long serialVersionUID = 1L;
255 private final ImmutableSet<YangExpr> predicates;
257 UnresolvedQNameStepWithPredicates(final YangXPathAxis axis, final UnresolvedQName qname,
258 final ImmutableSet<YangExpr> predicates) {
260 this.predicates = requireNonNull(predicates);
264 public ImmutableSet<YangExpr> getPredicates() {
269 public static sealed class NodeTypeStep extends Step {
270 private static final long serialVersionUID = 1L;
272 private final YangXPathNodeType nodeType;
274 NodeTypeStep(final YangXPathAxis axis, final YangXPathNodeType nodeType) {
276 this.nodeType = requireNonNull(nodeType);
279 public final YangXPathNodeType getNodeType() {
284 public int hashCode() {
285 return Objects.hash(getAxis(), nodeType, getPredicates());
289 public boolean equals(@Nullable final Object obj) {
293 if (obj == null || !getClass().equals(obj.getClass())) {
296 final NodeTypeStep other = (NodeTypeStep) obj;
297 return nodeType.equals(other.nodeType) && getAxis().equals(other.getAxis())
298 && getPredicates().equals(other.getPredicates());
302 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
303 return super.addToStringAttributes(helper).add("nodeType", nodeType);
307 @SuppressFBWarnings(value = "EQ_DOESNT_OVERRIDE_EQUALS",
308 justification = "https://github.com/spotbugs/spotbugs/issues/511")
309 static final class NodeTypeStepWithPredicates extends NodeTypeStep {
310 private static final long serialVersionUID = 1L;
312 private final ImmutableSet<YangExpr> predicates;
314 NodeTypeStepWithPredicates(final YangXPathAxis axis, final YangXPathNodeType type,
315 final ImmutableSet<YangExpr> predicates) {
317 this.predicates = requireNonNull(predicates);
321 public ImmutableSet<YangExpr> getPredicates() {
326 public static sealed class ProcessingInstructionStep extends NodeTypeStep {
327 private static final long serialVersionUID = 1L;
329 private final String name;
331 ProcessingInstructionStep(final YangXPathAxis axis, final String name) {
332 super(axis, YangXPathNodeType.PROCESSING_INSTRUCTION);
333 this.name = requireNonNull(name);
336 public final String getName() {
341 public final int hashCode() {
342 return Objects.hash(getAxis(), getNodeType(), name, getPredicates());
346 public final boolean equals(final @Nullable Object obj) {
347 return obj == this || super.equals(obj) && name.equals(((ProcessingInstructionStep) obj).name);
351 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
352 return super.addToStringAttributes(helper).add("name", name);
356 static final class ProcessingInstructionStepWithPredicates extends ProcessingInstructionStep {
357 private static final long serialVersionUID = 1L;
359 private final ImmutableSet<YangExpr> predicates;
361 ProcessingInstructionStepWithPredicates(final YangXPathAxis axis, final String name,
362 final ImmutableSet<YangExpr> predicates) {
364 this.predicates = requireNonNull(predicates);
368 public ImmutableSet<YangExpr> getPredicates() {
373 public static final class Absolute extends YangLocationPath {
374 private static final long serialVersionUID = 1L;
376 Absolute(final ImmutableList<Step> steps) {
381 public boolean isAbsolute() {
386 public static final class Relative extends YangLocationPath {
387 private static final long serialVersionUID = 1L;
389 Relative(final ImmutableList<Step> steps) {
394 public boolean isAbsolute() {
399 private static final long serialVersionUID = 1L;
400 private static final Absolute ROOT = new Absolute(ImmutableList.of());
401 private static final Relative SELF = new Relative(ImmutableList.of());
403 private final ImmutableList<Step> steps;
405 private YangLocationPath(final ImmutableList<Step> steps) {
406 this.steps = requireNonNull(steps);
409 public static final Absolute absolute(final Step... steps) {
410 return absolute(Arrays.asList(steps));
413 public static final Absolute absolute(final Collection<Step> steps) {
414 return steps.isEmpty() ? ROOT : new Absolute(ImmutableList.copyOf(steps));
417 public static final Relative relative(final Step... steps) {
418 return relative(Arrays.asList(steps));
421 public static final Relative relative(final Collection<Step> steps) {
422 return steps.isEmpty() ? SELF : new Relative(ImmutableList.copyOf(steps));
426 * The conceptual {@code root} {@link YangLocationPath}. This path is an absolute path and has no steps.
428 * @return Empty absolute {@link YangLocationPath}
430 public static final Absolute root() {
435 * The conceptual {@code same} {@link YangLocationPath}. This path is a relative path and has no steps and is
436 * equivalent to a step along {@link YangXPathAxis#SELF}.
438 * @return Empty relative {@link YangLocationPath}
440 public static final Relative self() {
444 public final ImmutableList<Step> getSteps() {
448 public abstract boolean isAbsolute();
451 public final int hashCode() {
452 return Boolean.hashCode(isAbsolute()) * 31 + steps.hashCode();
456 public final boolean equals(final @Nullable Object obj) {
457 return this == obj || obj instanceof YangLocationPath other && isAbsolute() == other.isAbsolute()
458 && steps.equals(other.steps);
462 public final String toString() {
463 final ToStringHelper helper = MoreObjects.toStringHelper(YangLocationPath.class).add("absolute", isAbsolute());
464 if (!steps.isEmpty()) {
465 helper.add("steps", steps);
467 return helper.toString();
470 final Object readSolve() {
471 return steps.isEmpty() ? isAbsolute() ? ROOT : SELF : this;