import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
-import com.google.common.annotations.Beta;
-import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.binding.ChildOf;
import org.opendaylight.yangtools.binding.ChoiceIn;
import org.opendaylight.yangtools.binding.DataObject;
+import org.opendaylight.yangtools.binding.DataObjectIdentifier;
+import org.opendaylight.yangtools.binding.DataObjectReference;
import org.opendaylight.yangtools.binding.DataObjectStep;
import org.opendaylight.yangtools.binding.DataRoot;
import org.opendaylight.yangtools.binding.ExactDataObjectStep;
import org.opendaylight.yangtools.binding.KeylessStep;
import org.opendaylight.yangtools.binding.NodeStep;
import org.opendaylight.yangtools.binding.impl.AbstractDataObjectReference;
+import org.opendaylight.yangtools.binding.impl.AbstractDataObjectReferenceBuilder;
import org.opendaylight.yangtools.concepts.HierarchicalIdentifier;
-import org.opendaylight.yangtools.util.HashCodeBuilder;
/**
* This instance identifier uniquely identifies a specific DataObject in the data tree modeled by YANG.
@java.io.Serial
private static final long serialVersionUID = 3L;
- /*
- * Protected to differentiate internal and external access. Internal access is required never to modify
- * the contents. References passed to outside entities have to be wrapped in an unmodifiable view.
- */
- final Iterable<DataObjectStep<?>> pathArguments;
-
- private final @NonNull Class<T> targetType;
private final boolean wildcarded;
- private final int hash;
- InstanceIdentifier(final Class<T> type, final Iterable<DataObjectStep<?>> pathArguments, final boolean wildcarded,
- final int hash) {
- this.pathArguments = requireNonNull(pathArguments);
- targetType = requireNonNull(type);
+ InstanceIdentifier(final Iterable<? extends @NonNull DataObjectStep<?>> steps, final boolean wildcarded) {
+ super(steps);
this.wildcarded = wildcarded;
- this.hash = hash;
}
/**
* @return Target type
*/
public final @NonNull Class<T> getTargetType() {
- return targetType;
+ return lastStep().type();
}
/**
*/
@SuppressWarnings("unchecked")
public final <N extends DataObject> @NonNull InstanceIdentifier<N> verifyTarget(final Class<@NonNull N> target) {
- verify(target.equals(targetType), "Cannot adapt %s to %s", this, target);
+ verify(target.equals(getTargetType()), "Cannot adapt %s to %s", this, target);
return (InstanceIdentifier<N>) this;
}
- @Override
- public final @NonNull Iterable<@NonNull DataObjectStep<?>> steps() {
- return Iterables.unmodifiableIterable(pathArguments);
- }
-
@Override
public final boolean isExact() {
return !wildcarded;
}
@Override
- public final int hashCode() {
- return hash;
- }
-
- @Override
- public final boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
-
- final var other = (InstanceIdentifier<?>) obj;
- if (pathArguments == other.pathArguments) {
- return true;
- }
-
- /*
- * We could now just go and compare the pathArguments, but that can be potentially expensive. Let's try to avoid
- * that by checking various things that we have cached from pathArguments and trying to prove the identifiers
- * are *not* equal.
- */
- return hash == other.hash && wildcarded == other.wildcarded && targetType == other.targetType
- && keyEquals(other)
- // Everything checks out so far, so we have to do a full equals
- && Iterables.elementsEqual(pathArguments, other.pathArguments);
- }
-
- boolean keyEquals(final InstanceIdentifier<?> other) {
- return true;
+ public final InstanceIdentifier<T> toLegacy() {
+ return this;
}
@Override
protected final Class<?> contract() {
- return getClass();
- }
-
- @Override
- protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
- return toStringHelper.add("targetType", targetType).add("path", Iterables.toString(pathArguments));
+ return wildcarded ? super.contract() : DataObjectIdentifier.class;
}
/**
public final <I extends DataObject> @Nullable InstanceIdentifier<I> firstIdentifierOf(
final Class<@NonNull I> type) {
int count = 1;
- for (var step : pathArguments) {
+ for (var step : steps()) {
if (type.equals(step.type())) {
@SuppressWarnings("unchecked")
- final var ret = (InstanceIdentifier<I>) internalCreate(Iterables.limit(pathArguments, count));
+ final var ret = (InstanceIdentifier<I>) internalCreate(Iterables.limit(steps(), count));
return ret;
}
*/
public final <N extends KeyAware<K> & DataObject, K extends Key<N>> @Nullable K firstKeyOf(
final Class<@NonNull N> listItem) {
- for (var step : pathArguments) {
+ for (var step : steps()) {
if (step instanceof KeyStep<?, ?> keyPredicate && listItem.equals(step.type())) {
@SuppressWarnings("unchecked")
final var ret = (K) keyPredicate.key();
public final boolean contains(final InstanceIdentifier<? extends DataObject> other) {
requireNonNull(other, "other should not be null");
- final var oit = other.pathArguments.iterator();
- for (var step : pathArguments) {
+ final var oit = other.steps().iterator();
+ for (var step : steps()) {
if (!oit.hasNext()) {
return false;
}
public final boolean containsWildcarded(final InstanceIdentifier<?> other) {
requireNonNull(other, "other should not be null");
- final var otherSteps = other.pathArguments.iterator();
- for (var step : pathArguments) {
+ final var otherSteps = other.steps().iterator();
+ for (var step : steps()) {
if (!otherSteps.hasNext()) {
return false;
}
}
private <N extends DataObject> @NonNull InstanceIdentifier<N> childIdentifier(final DataObjectStep<N> arg) {
- return trustedCreate(arg, Iterables.concat(pathArguments, Collections.singleton(arg)),
- HashCodeBuilder.nextHashCode(hash, arg), wildcarded);
+ return trustedCreate(arg, concat(steps(), arg), wildcarded);
}
/**
*/
public final <N extends ChildOf<? super T>> @NonNull InstanceIdentifier<N> child(
final Class<@NonNull N> container) {
- return childIdentifier(createStep(container));
+ return childIdentifier(DataObjectStep.of(container));
}
/**
// FIXME: add a proper caller
public final <C extends ChoiceIn<? super T> & DataObject, N extends ChildOf<? super C>>
@NonNull InstanceIdentifier<N> child(final Class<@NonNull C> caze, final Class<@NonNull N> container) {
- return childIdentifier(createStep(caze, container));
+ return childIdentifier(DataObjectStep.of(caze, container));
}
/**
@Override
protected Object toSerialForm() {
- return new IIv4<>(this);
+ return new IIv5(this);
}
@java.io.Serial
* @throws NullPointerException if {@code container} is null
*/
public static <T extends ChildOf<? extends DataRoot>> @NonNull Builder<T> builder(
- final Class<T> container) {
- return new RegularBuilder<>(createStep(container));
+ final @NonNull Class<T> container) {
+ return new RegularBuilder<>(DataObjectStep.of(container));
}
/**
* @throws NullPointerException if any argument is null
*/
public static <C extends ChoiceIn<? extends DataRoot> & DataObject, T extends ChildOf<? super C>>
- @NonNull Builder<T> builder(final Class<C> caze, final Class<T> container) {
- return new RegularBuilder<>(createStep(caze, container));
+ @NonNull Builder<T> builder(final @NonNull Class<C> caze, final @NonNull Class<T> container) {
+ return new RegularBuilder<>(DataObjectStep.of(caze, container));
}
/**
*/
public static <C extends ChoiceIn<? extends DataRoot> & DataObject,
N extends KeyAware<K> & ChildOf<? super C>, K extends Key<N>>
- @NonNull KeyedBuilder<N, K> builder(final Class<C> caze, final Class<N> listItem,
- final K listKey) {
+ @NonNull KeyedBuilder<N, K> builder(final @NonNull Class<C> caze, final @NonNull Class<N> listItem,
+ final @NonNull K listKey) {
return new KeyedBuilder<>(new KeyStep<>(listItem, requireNonNull(caze), listKey));
}
public static <R extends DataRoot & DataObject, T extends ChildOf<? super R>>
- @NonNull Builder<T> builderOfInherited(final Class<R> root, final Class<T> container) {
+ @NonNull Builder<T> builderOfInherited(final @NonNull Class<R> root, final @NonNull Class<T> container) {
// FIXME: we are losing root identity, hence namespaces may not work correctly
- return new RegularBuilder<>(createStep(container));
+ return new RegularBuilder<>(DataObjectStep.of(container));
}
public static <R extends DataRoot & DataObject, C extends ChoiceIn<? super R> & DataObject,
@NonNull Builder<T> builderOfInherited(final Class<R> root,
final Class<C> caze, final Class<T> container) {
// FIXME: we are losing root identity, hence namespaces may not work correctly
- return new RegularBuilder<>(createStep(caze, container));
+ return new RegularBuilder<>(DataObjectStep.of(caze, container));
}
public static <R extends DataRoot & DataObject, N extends KeyAware<K> & ChildOf<? super R>,
K extends Key<N>>
- @NonNull KeyedBuilder<N, K> builderOfInherited(final Class<R> root,
- final Class<N> listItem, final K listKey) {
+ @NonNull KeyedBuilder<N, K> builderOfInherited(final @NonNull Class<R> root,
+ final @NonNull Class<N> listItem, final @NonNull K listKey) {
// FIXME: we are losing root identity, hence namespaces may not work correctly
return new KeyedBuilder<>(new KeyStep<>(listItem, listKey));
}
return new KeyedBuilder<>(new KeyStep<>(listItem, requireNonNull(caze), listKey));
}
- @Beta
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public static <T extends DataObject, C extends ChoiceIn<?> & DataObject> @NonNull DataObjectStep<T> createStep(
- final Class<C> caze, final Class<T> type) {
- return KeyAware.class.isAssignableFrom(type) ? new KeylessStep(type, caze) : new NodeStep<>(type, caze);
- }
-
- @Beta
- public static <T extends DataObject> @NonNull DataObjectStep<T> createStep(final Class<T> type) {
- return createStep(null, type);
- }
-
/**
* Create an instance identifier for a very specific object type. This method implements {@link #create(Iterable)}
* semantics, except it is used by internal callers, which have assured that the argument is an immutable Iterable.
* @throws IllegalArgumentException if pathArguments is empty or contains a null element.
* @throws NullPointerException if {@code pathArguments} is null
*/
- private static @NonNull InstanceIdentifier<?> internalCreate(final Iterable<DataObjectStep<?>> pathArguments) {
+ private static @NonNull InstanceIdentifier<?> internalCreate(
+ final Iterable<? extends DataObjectStep<?>> pathArguments) {
final var it = requireNonNull(pathArguments, "pathArguments may not be null").iterator();
checkArgument(it.hasNext(), "pathArguments may not be empty");
- final var hashBuilder = new HashCodeBuilder<DataObjectStep<?>>();
boolean wildcard = false;
DataObjectStep<?> arg;
checkArgument(ChildOf.class.isAssignableFrom(type) || Augmentation.class.isAssignableFrom(type),
"%s is not a valid path argument", type);
- hashBuilder.addArgument(arg);
-
if (!(arg instanceof ExactDataObjectStep)) {
wildcard = true;
}
} while (it.hasNext());
- return trustedCreate(arg, pathArguments, hashBuilder.build(), wildcard);
+ return trustedCreate(arg, pathArguments, wildcard);
}
/**
@SuppressWarnings("unchecked")
public static <T extends ChildOf<? extends DataRoot>> @NonNull InstanceIdentifier<T> create(
final Class<@NonNull T> type) {
- return (InstanceIdentifier<T>) internalCreate(ImmutableList.of(createStep(type)));
+ return (InstanceIdentifier<T>) internalCreate(ImmutableList.of(DataObjectStep.of(type)));
}
/**
@SuppressWarnings({ "unchecked", "rawtypes" })
static <N extends DataObject> @NonNull InstanceIdentifier<N> trustedCreate(final DataObjectStep<?> lastStep,
- final Iterable<DataObjectStep<?>> pathArguments, final int hash, final boolean wildcarded) {
- // FIXME: use a switch expression
- if (lastStep instanceof NodeStep) {
- return new InstanceIdentifier(lastStep.type(), pathArguments, wildcarded, hash);
- } else if (lastStep instanceof KeyStep<?, ?> predicate) {
- return new KeyedInstanceIdentifier(predicate, pathArguments, wildcarded, hash);
- } else if (lastStep instanceof KeylessStep) {
- return new InstanceIdentifier(lastStep.type(), pathArguments, true, hash);
- } else {
- throw new IllegalStateException("Unhandled step " + lastStep);
- }
+ final Iterable<? extends DataObjectStep<?>> pathArguments, final boolean wildcarded) {
+ return switch (lastStep) {
+ case NodeStep<?> cast -> new InstanceIdentifier(pathArguments, wildcarded);
+ case KeyStep<?, ?> cast -> new KeyedInstanceIdentifier(pathArguments, wildcarded);
+ case KeylessStep<?> cast -> new InstanceIdentifier(pathArguments, true);
+ };
}
@Deprecated(since = "13.0.0", forRemoval = true)
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
final DataObjectStep<?> toStep() {
- return createStep((Class) caseType(), type());
+ return DataObjectStep.of((Class) caseType(), type());
}
@Override
*
* @param <T> Instance identifier target type
*/
- public abstract static sealed class Builder<T extends DataObject> {
- private final ImmutableList.Builder<DataObjectStep<?>> pathBuilder;
- private final HashCodeBuilder<DataObjectStep<?>> hashBuilder;
- private final Iterable<? extends DataObjectStep<?>> basePath;
-
- private boolean wildcard;
-
+ public abstract static sealed class Builder<T extends DataObject> extends AbstractDataObjectReferenceBuilder<T> {
Builder(final Builder<?> prev, final DataObjectStep<?> item) {
- pathBuilder = prev.pathBuilder;
- hashBuilder = prev.hashBuilder;
- basePath = prev.basePath;
- wildcard = prev.wildcard;
- appendItem(item);
+ super(prev, item);
}
Builder(final InstanceIdentifier<T> identifier) {
- pathBuilder = ImmutableList.builder();
- hashBuilder = new HashCodeBuilder<>(identifier.hashCode());
- wildcard = identifier.isWildcarded();
- basePath = identifier.pathArguments;
+ super(identifier);
}
Builder(final DataObjectStep<?> item, final boolean wildcard) {
- pathBuilder = ImmutableList.builder();
- hashBuilder = new HashCodeBuilder<>();
- basePath = null;
- hashBuilder.addArgument(item);
- pathBuilder.add(item);
- this.wildcard = wildcard;
- }
-
- final boolean wildcard() {
- return wildcard;
+ super(item, wildcard);
}
- /**
- * Build an identifier which refers to a specific augmentation of the current InstanceIdentifier referenced by
- * the builder.
- *
- * @param container augmentation class
- * @param <N> augmentation type
- * @return this builder
- * @throws NullPointerException if {@code container} is null
- */
+ @Override
public final <N extends DataObject & Augmentation<? super T>> Builder<N> augmentation(
- final Class<N> container) {
- return append(new NodeStep<>(container));
+ final Class<N> augmentation) {
+ return append(new NodeStep<>(augmentation));
}
- /**
- * Append the specified container as a child of the current InstanceIdentifier referenced by the builder. This
- * method should be used when you want to build an instance identifier by appending top-level elements, for
- * example
- * <pre>
- * InstanceIdentifier.builder().child(Nodes.class).build();
- * </pre>
- *
- * <p>
- * NOTE :- The above example is only for illustration purposes InstanceIdentifier.builder() has been deprecated
- * and should not be used. Use InstanceIdentifier.builder(Nodes.class) instead
- *
- * @param container Container to append
- * @param <N> Container type
- * @return this builder
- * @throws NullPointerException if {@code container} is null
- */
+ @Override
public final <N extends ChildOf<? super T>> Builder<N> child(final Class<N> container) {
- return append(createStep(container));
+ return append(DataObjectStep.of(container));
}
- /**
- * Append the specified container as a child of the current InstanceIdentifier referenced by the builder. This
- * method should be used when you want to build an instance identifier by appending a container node to the
- * identifier and the {@code container} is defined in a {@code grouping} used in a {@code case} statement.
- *
- * @param caze Choice case class
- * @param container Container to append
- * @param <C> Case type
- * @param <N> Container type
- * @return this builder
- * @throws NullPointerException if {@code container} is null
- */
+ @Override
public final <C extends ChoiceIn<? super T> & DataObject, N extends ChildOf<? super C>> Builder<N> child(
final Class<C> caze, final Class<N> container) {
- return append(createStep(caze, container));
+ return append(DataObjectStep.of(caze, container));
}
- /**
- * Append the specified listItem as a child of the current InstanceIdentifier referenced by the builder. This
- * method should be used when you want to build an instance identifier by appending a specific list element to
- * the identifier.
- *
- * @param listItem List to append
- * @param listKey List key
- * @param <N> List type
- * @param <K> Key type
- * @return this builder
- * @throws NullPointerException if any argument is null
- */
+ @Override
public final <N extends KeyAware<K> & ChildOf<? super T>, K extends Key<N>> KeyedBuilder<N, K> child(
final Class<@NonNull N> listItem, final K listKey) {
return append(new KeyStep<>(listItem, listKey));
}
- /**
- * Append the specified listItem as a child of the current InstanceIdentifier referenced by the builder. This
- * method should be used when you want to build an instance identifier by appending a specific list element to
- * the identifier and the {@code list} is defined in a {@code grouping} used in a {@code case} statement.
- *
- * @param caze Choice case class
- * @param listItem List to append
- * @param listKey List key
- * @param <C> Case type
- * @param <N> List type
- * @param <K> Key type
- * @return this builder
- * @throws NullPointerException if any argument is null
- */
+ @Override
public final <C extends ChoiceIn<? super T> & DataObject, K extends Key<N>,
N extends KeyAware<K> & ChildOf<? super C>> KeyedBuilder<N, K> child(final Class<C> caze,
final Class<N> listItem, final K listKey) {
return append(new KeyStep<>(listItem, requireNonNull(caze), listKey));
}
- /**
- * Build the instance identifier.
- *
- * @return Resulting {@link InstanceIdentifier}.
- */
+ @Override
public abstract @NonNull InstanceIdentifier<T> build();
@Override
- public final int hashCode() {
- return hashBuilder.build();
- }
+ protected abstract <X extends DataObject> @NonNull RegularBuilder<X> append(DataObjectStep<X> step);
@Override
- public final boolean equals(final Object obj) {
- return this == obj || obj instanceof Builder<?> other
- && wildcard == other.wildcard && hashCode() == other.hashCode()
- && Iterables.elementsEqual(pathArguments(), other.pathArguments());
- }
-
- final Iterable<DataObjectStep<?>> pathArguments() {
- final var args = pathBuilder.build();
- return basePath == null ? args : Iterables.concat(basePath, args);
- }
-
- final void appendItem(final DataObjectStep<?> item) {
- hashBuilder.addArgument(item);
- pathBuilder.add(item);
- if (!(item instanceof ExactDataObjectStep)) {
- wildcard = true;
- }
- }
-
- abstract <X extends DataObject> @NonNull RegularBuilder<X> append(DataObjectStep<X> step);
-
- abstract <X extends DataObject & KeyAware<Y>, Y extends Key<X>> @NonNull KeyedBuilder<X, Y> append(
+ protected abstract <X extends DataObject & KeyAware<Y>, Y extends Key<X>> @NonNull KeyedBuilder<X, Y> append(
KeyStep<Y, X> step);
}
public static final class KeyedBuilder<T extends DataObject & KeyAware<K>, K extends Key<T>>
- extends Builder<T> {
- private @NonNull KeyStep<K, T> lastStep;
-
+ extends Builder<T> implements DataObjectReference.Builder.WithKey<T, K> {
KeyedBuilder(final KeyStep<K, T> firstStep) {
super(firstStep, false);
- lastStep = requireNonNull(firstStep);
}
KeyedBuilder(final KeyedInstanceIdentifier<T, K> identifier) {
super(identifier);
- lastStep = identifier.lastStep();
}
private KeyedBuilder(final RegularBuilder<?> prev, final KeyStep<K, T> lastStep) {
super(prev, lastStep);
- this.lastStep = requireNonNull(lastStep);
}
/**
*/
@Override
public @NonNull KeyedInstanceIdentifier<T, K> build() {
- return new KeyedInstanceIdentifier<>(lastStep, pathArguments(), wildcard(), hashCode());
+ return new KeyedInstanceIdentifier<>(buildSteps(), wildcard());
}
@Override
- <X extends DataObject> @NonNull RegularBuilder<X> append(final DataObjectStep<X> step) {
+ protected <X extends DataObject> @NonNull RegularBuilder<X> append(final DataObjectStep<X> step) {
return new RegularBuilder<>(this, step);
}
@Override
@SuppressWarnings("unchecked")
- <X extends DataObject & KeyAware<Y>, Y extends Key<X>> KeyedBuilder<X, Y> append(final KeyStep<Y, X> step) {
+ protected <X extends DataObject & KeyAware<Y>, Y extends Key<X>> KeyedBuilder<X, Y> append(
+ final KeyStep<Y, X> step) {
appendItem(step);
- lastStep = (KeyStep<K, T>) requireNonNull(step);
return (KeyedBuilder<X, Y>) this;
}
}
private static final class RegularBuilder<T extends DataObject> extends Builder<T> {
- private @NonNull Class<T> type;
-
RegularBuilder(final DataObjectStep<T> item) {
super(item, !(item instanceof ExactDataObjectStep));
- type = item.type();
}
RegularBuilder(final InstanceIdentifier<T> identifier) {
super(identifier);
- type = identifier.getTargetType();
}
private RegularBuilder(final KeyedBuilder<?, ?> prev, final DataObjectStep<T> item) {
super(prev, item);
- type = item.type();
}
@Override
public InstanceIdentifier<T> build() {
- return new InstanceIdentifier<>(type, pathArguments(), wildcard(), hashCode());
+ return new InstanceIdentifier<>(buildSteps(), wildcard());
}
@Override
- @SuppressWarnings({ "rawtypes", "unchecked" })
- <X extends DataObject> RegularBuilder<X> append(final DataObjectStep<X> step) {
+ @SuppressWarnings("unchecked")
+ protected <X extends DataObject> RegularBuilder<X> append(final DataObjectStep<X> step) {
appendItem(step);
- type = (Class) step.type();
return (RegularBuilder<X>) this;
}
@Override
- <X extends DataObject & KeyAware<Y>, Y extends Key<X>> KeyedBuilder<X, Y> append(
+ protected <X extends DataObject & KeyAware<Y>, Y extends Key<X>> KeyedBuilder<X, Y> append(
final KeyStep<Y, X> item) {
return new KeyedBuilder<>(this, item);
}