*/
package org.opendaylight.yangtools.yang.data.api;
-import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import com.google.common.annotations.Beta;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import java.io.Serializable;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Array;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Arrays;
+import java.util.Base64;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
import java.util.function.Function;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.concepts.HierarchicalIdentifier;
-import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.concepts.AbstractHierarchicalIdentifier;
+import org.opendaylight.yangtools.concepts.Identifier;
import org.opendaylight.yangtools.concepts.Mutable;
import org.opendaylight.yangtools.util.ImmutableOffsetMap;
import org.opendaylight.yangtools.util.SingletonSet;
* <li>{@link NodeWithValue} - Identifier of instance {@code leaf} node or {@code leaf-list} node</li>
* </ul>
*
- * @see <a href="http://tools.ietf.org/html/rfc6020#section-9.13">RFC6020</a>
+ * @see <a href="http://www.rfc-editor.org/rfc/rfc6020#section-9.13">RFC6020</a>
*/
-public abstract sealed class YangInstanceIdentifier implements HierarchicalIdentifier<YangInstanceIdentifier>
+public abstract sealed class YangInstanceIdentifier
+ extends AbstractHierarchicalIdentifier<YangInstanceIdentifier, YangInstanceIdentifier.PathArgument>
permits FixedYangInstanceIdentifier, StackedYangInstanceIdentifier {
@java.io.Serial
private static final long serialVersionUID = 4L;
* namespace.
*
* @return An empty YangInstanceIdentifier
+ * @deprecated Use {@link #of()} instead.
*/
- public static @NonNull YangInstanceIdentifier empty() {
+ @Deprecated(since = "11.0.0", forRemoval = true)
+ public static final @NonNull YangInstanceIdentifier empty() {
+ return of();
+ }
+
+ /**
+ * Return an empty {@link YangInstanceIdentifier}. It corresponds to the path of the conceptual root of the YANG
+ * namespace.
+ *
+ * @return An empty YangInstanceIdentifier
+ */
+ public static final @NonNull YangInstanceIdentifier of() {
return FixedYangInstanceIdentifier.EMPTY_INSTANCE;
}
+ /**
+ * Returns a new InstanceIdentifier with only one path argument of type {@link PathArgument}.
+ *
+ * @param name QName of first node identifier
+ * @return A YangInstanceIdentifier
+ * @throws NullPointerException if {@code name} is {@code null}
+ */
+ public static final @NonNull YangInstanceIdentifier of(final PathArgument name) {
+ return new FixedYangInstanceIdentifier(ImmutableList.of(name));
+ }
+
+ /**
+ * Returns a new InstanceIdentifier composed of supplied {@link PathArgument}s.
+ *
+ * @param path Path arguments
+ * @return A YangInstanceIdentifier
+ * @throws NullPointerException if {@code path} or any of its components is {@code null}
+ */
+ public static final @NonNull YangInstanceIdentifier of(final PathArgument... path) {
+ // We are forcing a copy, since we cannot trust the user
+ return of(ImmutableList.copyOf(path));
+ }
+
+ /**
+ * Returns a new InstanceIdentifier composed of supplied {@link PathArgument}s.
+ *
+ * @param path Path arguments
+ * @return A YangInstanceIdentifier
+ * @throws NullPointerException if {@code path} is {@code null}
+ */
+ public static final @NonNull YangInstanceIdentifier of(final ImmutableList<PathArgument> path) {
+ return path.isEmpty() ? of() : new FixedYangInstanceIdentifier(path);
+ }
+
+ /**
+ * Returns a new InstanceIdentifier composed of supplied {@link PathArgument}s.
+ *
+ * @param path Path arguments
+ * @return A YangInstanceIdentifier
+ * @throws NullPointerException if {@code path} or any of its components is {@code null}
+ */
+ public static final @NonNull YangInstanceIdentifier of(final Collection<? extends PathArgument> path) {
+ return path.isEmpty() ? of() : of(ImmutableList.copyOf(path));
+ }
+
+ /**
+ * Returns a new InstanceIdentifier composed of supplied {@link PathArgument}s.
+ *
+ * @param path Path arguments
+ * @return A YangInstanceIdentifier
+ * @throws NullPointerException if {@code path} or any of its components is {@code null}
+ */
+ public static final @NonNull YangInstanceIdentifier of(final Iterable<? extends PathArgument> path) {
+ return of(ImmutableList.copyOf(path));
+ }
+
+ /**
+ * Returns a new {@link YangInstanceIdentifier} with only one path argument of type {@link NodeIdentifier} with
+ * supplied {@link QName}. Note this is a convenience method aimed at test code. Production code should consider
+ * using {@link #of(PathArgument)} instead.
+ *
+ * @param name QName of first {@link NodeIdentifier}
+ * @return A YangInstanceIdentifier
+ * @throws NullPointerException if {@code name} is {@code null}
+ */
+ public static final @NonNull YangInstanceIdentifier of(final QName name) {
+ return of(new NodeIdentifier(name));
+ }
+
+ /**
+ * Returns a new {@link YangInstanceIdentifier} with path arguments of type {@link NodeIdentifier} with
+ * supplied {@link QName}s. Note this is a convenience method aimed at test code. Production code should consider
+ * using {@link #of(PathArgument...)} instead.
+ *
+ * @param path QNames of {@link NodeIdentifier}s
+ * @return A YangInstanceIdentifier
+ * @throws NullPointerException if {@code path} or any of its components is {@code null}
+ */
+ public static final @NonNull YangInstanceIdentifier of(final QName... path) {
+ return of(Arrays.stream(path).map(NodeIdentifier::new).collect(ImmutableList.toImmutableList()));
+ }
+
+ /**
+ * Create a YangInstanceIdentifier composed of a single {@link PathArgument}.
+ *
+ * @param pathArgument Path argument
+ * @return A {@link YangInstanceIdentifier}
+ * @throws NullPointerException if {@code pathArgument} is null
+ * @deprecated Use {@link #of(NodeIdentifier)} instead.
+ */
+ @Deprecated(since = "11.0.0", forRemoval = true)
+ public static @NonNull YangInstanceIdentifier create(final PathArgument pathArgument) {
+ return of(pathArgument);
+ }
+
+ /**
+ * Create a YangInstanceIdentifier composed of specified {@link PathArgument}s.
+ *
+ * @param path Path arguments
+ * @return A {@link YangInstanceIdentifier}
+ * @throws NullPointerException if {@code path} or any of its components is {@code null}
+ * @deprecated Use {@link #of(PathArgument...)} instead.
+ */
+ @Deprecated(since = "11.0.0", forRemoval = true)
+ public static @NonNull YangInstanceIdentifier create(final PathArgument... path) {
+ return of(path);
+ }
+
+ /**
+ * Create a YangInstanceIdentifier composed of specified {@link PathArgument}s.
+ *
+ * @param path Path arguments
+ * @return A {@link YangInstanceIdentifier}
+ * @throws NullPointerException if {@code path} or any of its components is {@code null}
+ * @deprecated Use {@link #of(Iterable)} instead.
+ */
+ @Deprecated(since = "11.0.0", forRemoval = true)
+ public static @NonNull YangInstanceIdentifier create(final Iterable<? extends PathArgument> path) {
+ return of(path);
+ }
+
abstract @NonNull YangInstanceIdentifier createRelativeIdentifier(int skipFromRoot);
abstract @Nullable List<PathArgument> tryPathArguments();
abstract @Nullable List<PathArgument> tryReversePathArguments();
/**
- * Check if this instance identifier has empty path arguments, e.g. it is
- * empty and corresponds to {@link #empty()}.
+ * Check if this instance identifier has empty path arguments, e.g. it is empty and corresponds to {@link #of()}.
*
* @return True if this instance identifier is empty, false otherwise.
*/
* Return the conceptual parent {@link YangInstanceIdentifier}, which has
* one item less in {@link #getPathArguments()}.
*
- * @return Parent {@link YangInstanceIdentifier}, or null if this object is {@link #empty()}.
+ * @return Parent {@link YangInstanceIdentifier}, or null if this object is {@link #of()}.
*/
public abstract @Nullable YangInstanceIdentifier getParent();
* {@link #getPathArguments()}.
*
* @return Parent {@link YangInstanceIdentifier}
- * @throws VerifyException if this object is {@link #empty()}.
+ * @throws VerifyException if this object is {@link #of()}.
*/
public abstract @NonNull YangInstanceIdentifier coerceParent();
*/
public abstract PathArgument getLastPathArgument();
- public static @NonNull YangInstanceIdentifier create(final Iterable<? extends PathArgument> path) {
- return Iterables.isEmpty(path) ? empty() : new FixedYangInstanceIdentifier(ImmutableList.copyOf(path));
- }
-
- public static @NonNull YangInstanceIdentifier create(final PathArgument pathArgument) {
- return new FixedYangInstanceIdentifier(ImmutableList.of(pathArgument));
- }
-
- public static @NonNull YangInstanceIdentifier create(final PathArgument... path) {
- // We are forcing a copy, since we cannot trust the user
- return create(Arrays.asList(path));
- }
-
/**
* Create a {@link YangInstanceIdentifier} by taking a snapshot of provided path and iterating it backwards.
*
final ImmutableList.Builder<PathArgument> builder = ImmutableList.builderWithExpectedSize(
pathTowardsRoot.size());
pathTowardsRoot.descendingIterator().forEachRemaining(builder::add);
- return YangInstanceIdentifier.create(builder.build());
+ return YangInstanceIdentifier.of(builder.build());
}
/**
*/
public static <T> @NonNull YangInstanceIdentifier createReverse(final Deque<? extends T> stackTowardsRoot,
final Function<T, PathArgument> function) {
- final ImmutableList.Builder<PathArgument> builder = ImmutableList.builderWithExpectedSize(
- stackTowardsRoot.size());
- final Iterator<? extends T> it = stackTowardsRoot.descendingIterator();
+ final var builder = ImmutableList.<PathArgument>builderWithExpectedSize(stackTowardsRoot.size());
+ final var it = stackTowardsRoot.descendingIterator();
while (it.hasNext()) {
builder.add(function.apply(it.next()));
}
- return YangInstanceIdentifier.create(builder.build());
+ return YangInstanceIdentifier.of(builder.build());
}
boolean pathArgumentsEqual(final YangInstanceIdentifier other) {
*/
public Optional<YangInstanceIdentifier> relativeTo(final YangInstanceIdentifier ancestor) {
if (this == ancestor) {
- return Optional.of(empty());
+ return Optional.of(of());
}
if (ancestor.isEmpty()) {
return Optional.of(this);
}
- final Iterator<PathArgument> lit = getPathArguments().iterator();
- final Iterator<PathArgument> oit = ancestor.getPathArguments().iterator();
+ final var lit = getPathArguments().iterator();
int common = 0;
- while (oit.hasNext()) {
+ for (var element : ancestor.getPathArguments()) {
// Ancestor is not really an ancestor
- if (!lit.hasNext() || !lit.next().equals(oit.next())) {
+ if (!lit.hasNext() || !lit.next().equals(element)) {
return Optional.empty();
}
return Optional.of(this);
}
if (!lit.hasNext()) {
- return Optional.of(empty());
+ return Optional.of(of());
}
return Optional.of(createRelativeIdentifier(common));
}
@Override
- public final boolean contains(final YangInstanceIdentifier other) {
- if (this == other) {
- return true;
- }
+ protected final Iterator<PathArgument> itemIterator() {
+ return getPathArguments().iterator();
+ }
- checkArgument(other != null, "other should not be null");
- final Iterator<PathArgument> lit = getPathArguments().iterator();
- final Iterator<PathArgument> oit = other.getPathArguments().iterator();
+ @Override
+ protected final Object writeReplace() {
+ return new YIDv1(this);
+ }
- while (lit.hasNext()) {
- if (!oit.hasNext()) {
- return false;
- }
+ @java.io.Serial
+ private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ throwNSE();
+ }
- if (!lit.next().equals(oit.next())) {
- return false;
- }
- }
+ @java.io.Serial
+ private void readObjectNoData() throws ObjectStreamException {
+ throwNSE();
+ }
- return true;
+ @java.io.Serial
+ private void writeObject(final ObjectOutputStream stream) throws IOException {
+ throwNSE();
}
@Override
* The cache is thread-safe - if multiple computations occurs at the
* same time, cache will be overwritten with same result.
*/
- final String ret = (String) TO_STRING_CACHE.getAcquire(this);
+ final var ret = (String) TO_STRING_CACHE.getAcquire(this);
return ret != null ? ret : loadToString();
}
return 0;
}
- if (byte[].class.equals(value.getClass())) {
- return Arrays.hashCode((byte[]) value);
+ if (value instanceof byte[] bytes) {
+ return Arrays.hashCode(bytes);
}
if (value.getClass().isArray()) {
return hash;
}
- return Objects.hashCode(value);
+ return value.hashCode();
}
private int loadHashCode() {
abstract int computeHashCode();
- @java.io.Serial
- final Object writeReplace() {
- return new YIDv1(this);
- }
-
- // Static factories & helpers
-
- /**
- * Returns a new InstanceIdentifier with only one path argument of type {@link NodeIdentifier} with supplied
- * QName.
- *
- * @param name QName of first node identifier
- * @return Instance Identifier with only one path argument of type {@link NodeIdentifier}
- */
- public static @NonNull YangInstanceIdentifier of(final QName name) {
- return create(new NodeIdentifier(name));
- }
-
/**
* Returns new builder for InstanceIdentifier with empty path arguments.
*
* <li>{@link NodeWithValue} - Identifier of leaf-list entry
* </ul>
*/
- public abstract static sealed class PathArgument implements Comparable<PathArgument>, Immutable, Serializable {
+ public abstract static sealed class PathArgument implements Identifier, Comparable<PathArgument> {
@java.io.Serial
private static final long serialVersionUID = -4546547994250849340L;
@Override
@SuppressWarnings("checkstyle:equalsHashCode")
public boolean equals(final Object obj) {
- if (!super.equals(obj)) {
- return false;
- }
- final NodeWithValue<?> other = (NodeWithValue<?>) obj;
- return Objects.deepEquals(value, other.value);
+ return super.equals(obj) && Objects.deepEquals(value, ((NodeWithValue<?>) obj).value);
}
@Override
public String toString() {
- return super.toString() + '[' + value + ']';
+ final var str = super.toString();
+ return value instanceof byte[] bytes ? str + "[b64:" + Base64.getEncoder().encodeToString(bytes) + ']'
+ : str + '[' + value + ']';
}
@Override