*/
package org.opendaylight.yangtools.yang.data.api;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+import static java.util.Objects.requireNonNull;
+
import com.google.common.annotations.Beta;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
import java.io.Serializable;
import java.lang.reflect.Array;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import javax.annotation.Nonnull;
*
* @see <a href="http://tools.ietf.org/html/rfc6020#section-9.13">RFC6020</a>
*/
+// FIXME: 3.0.0: this concept needs to be moved to yang-common, as parser components need the ability to refer
+// to data nodes -- most notably XPath expressions and {@code default} statement arguments need to be able
+// to represent these.
public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentifier>, Immutable, Serializable {
/**
* An empty {@link YangInstanceIdentifier}. It corresponds to the path of the conceptual
return Optional.of(this);
}
- final Iterator<?> lit = getPathArguments().iterator();
- final Iterator<?> oit = ancestor.getPathArguments().iterator();
+ final Iterator<PathArgument> lit = getPathArguments().iterator();
+ final Iterator<PathArgument> oit = ancestor.getPathArguments().iterator();
int common = 0;
while (oit.hasNext()) {
// Ancestor is not really an ancestor
if (!lit.hasNext() || !lit.next().equals(oit.next())) {
- return Optional.absent();
+ return Optional.empty();
}
++common;
return true;
}
- Preconditions.checkArgument(other != null, "other should not be null");
- final Iterator<?> lit = getPathArguments().iterator();
- final Iterator<?> oit = other.getPathArguments().iterator();
+ checkArgument(other != null, "other should not be null");
+ final Iterator<PathArgument> lit = getPathArguments().iterator();
+ final Iterator<PathArgument> oit = other.getPathArguments().iterator();
while (lit.hasNext()) {
if (!oit.hasNext()) {
private transient volatile boolean hashGuard = false;
protected AbstractPathArgument(final QName nodeType) {
- this.nodeType = Preconditions.checkNotNull(nodeType);
+ this.nodeType = requireNonNull(nodeType);
}
@Override
this.keyValues = ImmutableOffsetMap.unorderedCopyOf(keyValues);
}
- public NodeIdentifierWithPredicates(final QName node, final QName key, final Object value) {
+ public NodeIdentifierWithPredicates(final QName node, final ImmutableOffsetMap<QName, Object> keyValues) {
+ super(node);
+ this.keyValues = requireNonNull(keyValues);
+ }
+
+ public NodeIdentifierWithPredicates(final QName node, final SharedSingletonMap<QName, Object> keyValues) {
super(node);
- this.keyValues = SharedSingletonMap.unorderedOf(key, value);
+ this.keyValues = requireNonNull(keyValues);
+ }
+
+ public NodeIdentifierWithPredicates(final QName node, final QName key, final Object value) {
+ this(node, SharedSingletonMap.unorderedOf(key, value));
}
public Map<QName, Object> getKeyValues() {
}
@Override
+ @SuppressWarnings("checkstyle:equalsHashCode")
public boolean equals(final Object obj) {
if (!super.equals(obj)) {
return false;
}
@Override
+ @SuppressWarnings("checkstyle:equalsHashCode")
public boolean equals(final Object obj) {
if (!super.equals(obj)) {
return false;
int thisSize = childNames.size();
int otherSize = otherChildNames.size();
if (thisSize == otherSize) {
- Iterator<QName> otherIterator = otherChildNames.iterator();
- for (QName name : childNames) {
- int child = name.compareTo(otherIterator.next());
- if (child != 0) {
- return child;
- }
+ // Quick Set-based comparison
+ if (childNames.equals(otherChildNames)) {
+ return 0;
}
- return 0;
+
+ // We already know the sets are not equal, but have equal size, hence the sets differ in their elements,
+ // but potentially share a common set of elements. The most consistent way of comparing them is using
+ // total ordering defined by QName's compareTo. Hence convert both sets to lists ordered
+ // by QName.compareTo() and decide on the first differing element.
+ final List<QName> diff = new ArrayList<>(Sets.symmetricDifference(childNames, otherChildNames));
+ verify(!diff.isEmpty(), "Augmentation identifiers %s and %s report no difference", this, o);
+ diff.sort(QName::compareTo);
+ return childNames.contains(diff.get(0)) ? -1 : 1;
} else if (thisSize < otherSize) {
return 1;
} else {
*/
public interface InstanceIdentifierBuilder extends Builder<YangInstanceIdentifier> {
/**
- * Adds a {@link PathArgument} to to path arguments of resulting instance identifier.
+ * Adds a {@link PathArgument} to path arguments of resulting instance identifier.
*
* @param arg A {@link PathArgument} to be added
* @return this builder
*/
InstanceIdentifierBuilder nodeWithKey(QName nodeType, QName key, Object value);
+ /**
+ * Adds a collection of {@link PathArgument}s to path arguments of resulting instance identifier.
+ *
+ * @param args {@link PathArgument}s to be added
+ * @return this builder
+ * @throws NullPointerException if any of the arguments is null
+ */
+ @Beta
+ InstanceIdentifierBuilder append(Collection<? extends PathArgument> args);
+
+ /**
+ * Adds a collection of {@link PathArgument}s to path arguments of resulting instance identifier.
+ *
+ * @param args {@link PathArgument}s to be added
+ * @return this builder
+ * @throws NullPointerException if any of the arguments is null
+ */
+ @Beta
+ default InstanceIdentifierBuilder append(final PathArgument... args) {
+ return append(Arrays.asList(args));
+ }
+
/**
* Builds an {@link YangInstanceIdentifier} with path arguments from this builder.
*