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;
30 public abstract class YangLocationPath implements YangExpr {
31 public abstract static class Step implements Serializable, YangPredicateAware {
32 private static final long serialVersionUID = 1L;
34 private final YangXPathAxis axis;
36 Step(final YangXPathAxis axis) {
37 this.axis = requireNonNull(axis);
40 public final YangXPathAxis getAxis() {
45 public abstract int hashCode();
48 public abstract boolean equals(@Nullable Object obj);
51 public final String toString() {
52 return addToStringAttributes(MoreObjects.toStringHelper(Step.class)).toString();
55 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
56 helper.add("axis", axis);
57 final Set<YangExpr> predicates = getPredicates();
58 if (!predicates.isEmpty()) {
59 helper.add("predicates", predicates);
65 public static class AxisStep extends Step {
66 private static final long serialVersionUID = 1L;
68 AxisStep(final YangXPathAxis axis) {
73 public final int hashCode() {
74 return Objects.hash(getAxis(), getPredicates());
78 public final boolean equals(@Nullable final Object obj) {
82 if (!(obj instanceof AxisStep)) {
85 final AxisStep other = (AxisStep) obj;
86 return getAxis().equals(other.getAxis()) && getPredicates().equals(other.getPredicates());
89 @SuppressFBWarnings(value = "SE_PRIVATE_READ_RESOLVE_NOT_INHERITED",
90 justification = "We have only one subclass, and that does not want to inherit this")
91 private Object readResolve() {
92 return getAxis().asStep();
96 static final class AxisStepWithPredicates extends AxisStep {
97 private static final long serialVersionUID = 1L;
99 private final ImmutableSet<YangExpr> predicates;
101 AxisStepWithPredicates(final YangXPathAxis axis, final ImmutableSet<YangExpr> predicates) {
103 this.predicates = requireNonNull(predicates);
107 public ImmutableSet<YangExpr> getPredicates() {
112 // match a particular namespace
113 public static class NamespaceStep extends Step {
114 private static final long serialVersionUID = 1L;
116 private final QNameModule namespace;
118 NamespaceStep(final YangXPathAxis axis, final QNameModule namespace) {
120 this.namespace = requireNonNull(namespace);
123 public final QNameModule getNamespace() {
128 public final int hashCode() {
129 return Objects.hash(getAxis(), namespace, getPredicates());
133 public final boolean equals(@Nullable final Object obj) {
137 if (!(obj instanceof NamespaceStep)) {
140 final NamespaceStep other = (NamespaceStep) obj;
141 return getAxis().equals(other.getAxis()) && namespace.equals(other.namespace)
142 && getPredicates().equals(other.getPredicates());
146 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
147 return super.addToStringAttributes(helper).add("namespace", namespace);
152 * A step along an axis. This may be either a {@link ResolvedQNameStep} or a {@link UnresolvedQNameStep}.
154 * @author Robert Varga
156 public abstract static class QNameStep extends Step implements QNameReferent {
157 private static final long serialVersionUID = 1L;
159 QNameStep(final YangXPathAxis axis) {
164 private abstract static class AbstractQNameStep<T extends AbstractQName> extends QNameStep {
165 private static final long serialVersionUID = 1L;
167 private final T qname;
169 AbstractQNameStep(final YangXPathAxis axis, final T qname) {
171 this.qname = requireNonNull(qname);
175 public final @NonNull T getQName() {
180 public final int hashCode() {
181 return Objects.hash(getAxis(), qname, getPredicates());
185 @SuppressFBWarnings(value = "EQ_UNUSUAL", justification = "Polymorphic via equalityClass()")
186 public final boolean equals(final @Nullable Object obj) {
190 final Class<? extends AbstractQNameStep<?>> eq = equalityClass();
191 if (!equalityClass().isInstance(obj)) {
195 final AbstractQNameStep<?> other = eq.cast(obj);
196 return getAxis().equals(other.getAxis()) && qname.equals(other.qname)
197 && getPredicates().equals(other.getPredicates());
201 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
202 return super.addToStringAttributes(helper).add("qname", qname);
205 abstract Class<? extends AbstractQNameStep<?>> equalityClass();
208 public static class ResolvedQNameStep extends AbstractQNameStep<QName> implements ResolvedQNameReferent {
209 private static final long serialVersionUID = 1L;
211 ResolvedQNameStep(final YangXPathAxis axis, final QName qname) {
215 static ResolvedQNameStep of(final YangXPathAxis axis, final QName qname,
216 final Collection<YangExpr> predicates) {
217 return predicates.isEmpty() ? new ResolvedQNameStep(axis, qname)
218 : new ResolvedQNameStepWithPredicates(axis, qname, ImmutableSet.copyOf(predicates));
222 final Class<ResolvedQNameStep> equalityClass() {
223 return ResolvedQNameStep.class;
227 private static final class ResolvedQNameStepWithPredicates extends ResolvedQNameStep {
228 private static final long serialVersionUID = 1L;
230 private final ImmutableSet<YangExpr> predicates;
232 ResolvedQNameStepWithPredicates(final YangXPathAxis axis, final QName qname,
233 final ImmutableSet<YangExpr> predicates) {
235 this.predicates = requireNonNull(predicates);
239 public ImmutableSet<YangExpr> getPredicates() {
244 public static class UnresolvedQNameStep extends AbstractQNameStep<AbstractQName>
245 implements UnresolvedQNameReferent<ResolvedQNameStep> {
246 private static final long serialVersionUID = 1L;
248 UnresolvedQNameStep(final YangXPathAxis axis, final AbstractQName qname) {
252 static UnresolvedQNameStep of(final YangXPathAxis axis, final AbstractQName qname,
253 final Collection<YangExpr> predicates) {
254 return predicates.isEmpty() ? new UnresolvedQNameStep(axis, qname)
255 : new UnresolvedQNameStepWithPredicates(axis, qname, ImmutableSet.copyOf(predicates));
259 final Class<UnresolvedQNameStep> equalityClass() {
260 return UnresolvedQNameStep.class;
264 private static final class UnresolvedQNameStepWithPredicates extends UnresolvedQNameStep {
265 private static final long serialVersionUID = 1L;
267 private final ImmutableSet<YangExpr> predicates;
269 UnresolvedQNameStepWithPredicates(final YangXPathAxis axis, final AbstractQName qname,
270 final ImmutableSet<YangExpr> predicates) {
272 this.predicates = requireNonNull(predicates);
276 public ImmutableSet<YangExpr> getPredicates() {
281 public static class NodeTypeStep extends Step {
282 private static final long serialVersionUID = 1L;
284 private final YangXPathNodeType nodeType;
286 NodeTypeStep(final YangXPathAxis axis, final YangXPathNodeType nodeType) {
288 this.nodeType = requireNonNull(nodeType);
291 public final YangXPathNodeType getNodeType() {
296 public int hashCode() {
297 return Objects.hash(getAxis(), nodeType, getPredicates());
301 public boolean equals(@Nullable final Object obj) {
305 if (obj == null || !getClass().equals(obj.getClass())) {
308 final NodeTypeStep other = (NodeTypeStep) obj;
309 return nodeType.equals(other.nodeType) && getAxis().equals(other.getAxis())
310 && getPredicates().equals(other.getPredicates());
314 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
315 return super.addToStringAttributes(helper).add("nodeType", nodeType);
319 @SuppressFBWarnings(value = "EQ_DOESNT_OVERRIDE_EQUALS",
320 justification = "https://github.com/spotbugs/spotbugs/issues/511")
321 static final class NodeTypeStepWithPredicates extends NodeTypeStep {
322 private static final long serialVersionUID = 1L;
324 private final ImmutableSet<YangExpr> predicates;
326 NodeTypeStepWithPredicates(final YangXPathAxis axis, final YangXPathNodeType type,
327 final ImmutableSet<YangExpr> predicates) {
329 this.predicates = requireNonNull(predicates);
333 public ImmutableSet<YangExpr> getPredicates() {
338 public static class ProcessingInstructionStep extends NodeTypeStep {
339 private static final long serialVersionUID = 1L;
341 private final String name;
343 ProcessingInstructionStep(final YangXPathAxis axis, final String name) {
344 super(axis, YangXPathNodeType.PROCESSING_INSTRUCTION);
345 this.name = requireNonNull(name);
348 public final String getName() {
353 public final int hashCode() {
354 return Objects.hash(getAxis(), getNodeType(), name, getPredicates());
358 public final boolean equals(final @Nullable Object obj) {
359 return obj == this || super.equals(obj) && name.equals(((ProcessingInstructionStep) obj).name);
363 protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
364 return super.addToStringAttributes(helper).add("name", name);
368 static final class ProcessingInstructionStepWithPredicates extends ProcessingInstructionStep {
369 private static final long serialVersionUID = 1L;
371 private final ImmutableSet<YangExpr> predicates;
373 ProcessingInstructionStepWithPredicates(final YangXPathAxis axis, final String name,
374 final ImmutableSet<YangExpr> predicates) {
376 this.predicates = requireNonNull(predicates);
380 public ImmutableSet<YangExpr> getPredicates() {
385 public static final class Absolute extends YangLocationPath {
386 private static final long serialVersionUID = 1L;
388 Absolute(final ImmutableList<Step> steps) {
393 public boolean isAbsolute() {
398 public static final class Relative extends YangLocationPath {
399 private static final long serialVersionUID = 1L;
401 Relative(final ImmutableList<Step> steps) {
406 public boolean isAbsolute() {
411 private static final long serialVersionUID = 1L;
412 private static final Absolute ROOT = new Absolute(ImmutableList.of());
413 private static final Relative SELF = new Relative(ImmutableList.of());
415 private final ImmutableList<Step> steps;
417 YangLocationPath(final ImmutableList<Step> steps) {
418 this.steps = requireNonNull(steps);
421 public static final Absolute absolute(final Step... steps) {
422 return absolute(Arrays.asList(steps));
425 public static final Absolute absolute(final Collection<Step> steps) {
426 return steps.isEmpty() ? ROOT : new Absolute(ImmutableList.copyOf(steps));
429 public static final Relative relative(final Step... steps) {
430 return relative(Arrays.asList(steps));
433 public static final Relative relative(final Collection<Step> steps) {
434 return steps.isEmpty() ? SELF : new Relative(ImmutableList.copyOf(steps));
438 * The conceptual {@code root} {@link YangLocationPath}. This path is an absolute path and has no steps.
440 * @return Empty absolute {@link YangLocationPath}
442 public static final Absolute root() {
447 * The conceptual {@code same} {@link YangLocationPath}. This path is a relative path and has no steps and is
448 * equivalent to a step along {@link YangXPathAxis#SELF}.
450 * @return Empty relative {@link YangLocationPath}
452 public static final Relative self() {
456 public final ImmutableList<Step> getSteps() {
460 public abstract boolean isAbsolute();
463 public final int hashCode() {
464 return Boolean.hashCode(isAbsolute()) * 31 + steps.hashCode();
468 public final boolean equals(final @Nullable Object obj) {
472 if (!(obj instanceof YangLocationPath)) {
475 final YangLocationPath other = (YangLocationPath) obj;
476 return isAbsolute() == other.isAbsolute() && steps.equals(other.steps);
480 public final String toString() {
481 final ToStringHelper helper = MoreObjects.toStringHelper(YangLocationPath.class).add("absolute", isAbsolute());
482 if (!steps.isEmpty()) {
483 helper.add("steps", steps);
485 return helper.toString();
488 final Object readSolve() {
489 return steps.isEmpty() ? isAbsolute() ? ROOT : SELF : this;