org.opendaylight.yangtools.binding.DataObjectReference Maven / Gradle / Ivy
/*
* Copyright (c) 2024 PANTHEON.tech, s.r.o. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.yangtools.binding;
import static java.util.Objects.requireNonNull;
import com.google.common.collect.ImmutableList;
import java.io.Serializable;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.binding.impl.AbstractDataObjectReference;
import org.opendaylight.yangtools.binding.impl.AbstractDataObjectReferenceBuilder;
import org.opendaylight.yangtools.binding.impl.DataObjectIdentifierImpl;
import org.opendaylight.yangtools.binding.impl.DataObjectReferenceBuilder;
import org.opendaylight.yangtools.binding.impl.DataObjectReferenceBuilderWithKey;
import org.opendaylight.yangtools.binding.impl.DataObjectReferenceImpl;
import org.opendaylight.yangtools.binding.impl.DataObjectReferenceWithKey;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.KeyedBuilder;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
/**
* A reference to a {@link DataObject} with semantics partially overlapping with to YANG {@code instance-identifier}.
*
*
* While this indirection is not something defined in YANG, this class hierarchy arises naturally from the Binding
* specification's Java footprint, which uses {@link DataObject} as the baseline self-sufficient addressable construct.
* This means users can use a {@link KeyAware} class without specifying the corresponding key -- resulting in an
* {@link InexactDataObjectStep}.
*
*
* There are two kinds of a reference based on their treatment of such a {@link InexactDataObjectStep}:
*
* - {@link DataObjectIdentifier}, which accepts only {@link ExactDataObjectStep}s and represents
* a {@link BindingInstanceIdentifier} pointing to a {@link DataObject}
* - {@link DataObjectReference}, which accepts any {@link DataObjectStep} and represents path-based matching
* criteria for one or more {@link DataObjectIdentifier}s based on
* {@link InexactDataObjectStep#matches(DataObjectStep)}.
*
* An explicit conversion to {@link DataObjectIdentifier} can be attempted via {@link #toIdentifier()} method.
*
*
* The legacy {@link InstanceIdentifier} is implements the second kind via its class hierarchy, but indicates its
* compliance via {@link #isExact()} method. Any {@link DataObjectReference} can be converted into an
* {@link InstanceIdentifier} via the {@link #toLegacy()} method.
*
* @param type of {@link DataObject} held in the last step.
*/
public sealed interface DataObjectReference extends Immutable, Serializable
permits DataObjectIdentifier, DataObjectReference.WithKey, AbstractDataObjectReference {
/**
* A builder of {@link DataObjectReference} objects.
*
* @param type of {@link DataObject} held in the last step.
*/
sealed interface Builder
permits Builder.WithKey, DataObjectIdentifier.Builder, AbstractDataObjectReferenceBuilder {
/**
* A builder of {@link DataObjectReference.WithKey} objects.
*
* @param type of {@link EntryObject} held in the last step.
* @param {@link Key} type
*/
sealed interface WithKey, K extends Key> extends Builder
permits DataObjectIdentifier.Builder.WithKey, DataObjectReferenceBuilderWithKey, KeyedBuilder {
@Override
DataObjectReference.WithKey build();
}
/**
* Update this builder to build a reference to a specific augmentation of the data object this builder currently
* points to.
*
* @param augmentation type
* @param augmentation augmentation class
* @return this builder
* @throws NullPointerException if {@code augmentation} is {@code null}
*/
> @NonNull Builder augmentation(@NonNull Class augmentation);
/**
* Append the specified container as a child of the data object this build currently references. This method
* should be used when you want to build an instance identifier by appending top-level elements.
*
* @param Container type
* @param container Container to append
* @return this builder
* @throws NullPointerException if {@code container} is null
*/
> @NonNull Builder child(@NonNull Class container);
/**
* Append the specified container as a child of the data object this build currently references. This method
* should be used when you want to build an reference 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 Case type
* @param Container type
* @param caze Choice case class
* @param container Container to append
* @return this builder
* @throws NullPointerException if {@code container} is null
*/
& DataObject, N extends ChildOf super C>> @NonNull Builder child(
Class caze, @NonNull Class container);
/**
* Append the specified listItem as a child of the data object this build currently references. This method
* should be used when you want to build a reference by appending a specific list element to the identifier.
*
* @param List type
* @param Key type
* @param listItem List to append
* @param listKey List key
* @return this builder
* @throws NullPointerException if any argument is null
*/
& ChildOf super T>, K extends Key> @NonNull WithKey child(
@NonNull Class<@NonNull N> listItem, @NonNull K listKey);
/**
* Append the specified listItem as a child of the data object this build currently references. This
* method should be used when you want to build a reference 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 Case type
* @param List type
* @param Key type
* @param caze Choice case class
* @param listItem List to append
* @param listKey List key
* @return this builder
* @throws NullPointerException if any argument is null
*/
& DataObject, K extends Key, N extends EntryObject & ChildOf super C>>
@NonNull WithKey child(@NonNull Class caze, @NonNull Class listItem, @NonNull K listKey);
/**
* Build the data object reference.
*
* @return resulting {@link DataObjectReference}.
*/
@NonNull DataObjectReference build();
}
/**
* A {@link DataObjectReference} pointing to a {@link EntryObject}.
*
* @param Key type
* @param EntryObject type
*/
sealed interface WithKey, K extends Key> extends DataObjectReference, KeyAware
permits DataObjectIdentifier.WithKey, DataObjectReferenceWithKey, KeyedInstanceIdentifier {
@Override
KeyStep lastStep();
@Override
Builder.WithKey toBuilder();
@Override
DataObjectIdentifier.WithKey toIdentifier();
@Override
default K key() {
return lastStep().key();
}
/**
* Return the key attached to this identifier. This method is equivalent to calling
* {@link InstanceIdentifier#keyOf(InstanceIdentifier)}.
*
* @return Key associated with this instance identifier.
* @deprecated Use {@link #key()} instead.
*/
@Deprecated(since = "14.0.0")
default @NonNull K getKey() {
return key();
}
}
/**
* Create a new {@link Builder} initialized to produce a reference equal to this one.
*
* @return A builder instance
* @deprecated Use {@link #toBuilder()} instead.
*/
@Deprecated(since = "14.0.0")
default @NonNull Builder builder() {
return toBuilder();
}
static >> @NonNull Builder builder(final @NonNull Class container) {
return new DataObjectReferenceBuilder<>(DataObjectStep.of(container));
}
static > & DataObject, T extends ChildOf super C>>
@NonNull Builder builder(final @NonNull Class caze, final @NonNull Class container) {
return new DataObjectReferenceBuilder<>(DataObjectStep.of(caze, container));
}
static & ChildOf extends DataRoot>>, K extends Key>
Builder.@NonNull WithKey builder(final Class listItem, final K listKey) {
return new DataObjectReferenceBuilderWithKey<>(new KeyStep<>(listItem, listKey));
}
static > & DataObject,
N extends EntryObject & ChildOf super C>, K extends Key>
Builder.@NonNull WithKey builder(final @NonNull Class caze, final @NonNull Class listItem,
final @NonNull K listKey) {
return new DataObjectReferenceBuilderWithKey<>(new KeyStep<>(listItem, requireNonNull(caze), listKey));
}
static , T extends ChildOf super R>>
@NonNull Builder builderOfInherited(final @NonNull Class root, final @NonNull Class container) {
// FIXME: we are losing root identity, hence namespaces may not work correctly
return new DataObjectReferenceBuilder<>(DataObjectStep.of(container));
}
static , C extends ChoiceIn super R> & DataObject, T extends ChildOf super C>>
@NonNull Builder builderOfInherited(final Class root,
final Class caze, final Class container) {
// FIXME: we are losing root identity, hence namespaces may not work correctly
return new DataObjectReferenceBuilder<>(DataObjectStep.of(caze, container));
}
static , N extends EntryObject & ChildOf super R>, K extends Key>
Builder.@NonNull WithKey builderOfInherited(final @NonNull Class root,
final @NonNull Class listItem, final @NonNull K listKey) {
// FIXME: we are losing root identity, hence namespaces may not work correctly
return new DataObjectReferenceBuilderWithKey<>(new KeyStep<>(listItem, listKey));
}
static , C extends ChoiceIn super R> & DataObject,
N extends EntryObject & ChildOf super C>, K extends Key>
Builder.@NonNull WithKey builderOfInherited(final Class root,
final Class caze, final Class listItem, final K listKey) {
// FIXME: we are losing root identity, hence namespaces may not work correctly
return new DataObjectReferenceBuilderWithKey<>(new KeyStep<>(listItem, requireNonNull(caze), listKey));
}
static @NonNull DataObjectReference> ofUnsafeSteps(final Iterable extends @NonNull DataObjectStep>> steps) {
return ofUnsafeSteps(ImmutableList.copyOf(steps));
}
static @NonNull DataObjectReference> ofUnsafeSteps(final List extends @NonNull DataObjectStep>> steps) {
return ofUnsafeSteps(ImmutableList.copyOf(steps));
}
@SuppressWarnings("unchecked")
static @NonNull DataObjectReference> ofUnsafeSteps(
final ImmutableList extends @NonNull DataObjectStep>> steps) {
if (steps.stream().allMatch(ExactDataObjectStep.class::isInstance)) {
return DataObjectIdentifierImpl.ofUnsafeSteps(
(ImmutableList extends @NonNull ExactDataObjectStep>>) steps);
}
return DataObjectReferenceImpl.ofUnsafeSteps(steps);
}
/**
* Return the steps of this reference. Returned {@link Iterable} does not support removals and contains one or more
* non-null items.
*
* @return the steps of this reference
*/
@NonNull Iterable extends @NonNull DataObjectStep>> steps();
/**
* Return the last step of this reference.
*
* @return the last step
*/
@NonNull DataObjectStep lastStep();
/**
* Create a new {@link Builder} initialized to produce a reference equal to this one.
*
* @return A builder instance
*/
@NonNull Builder toBuilder();
/**
* Return a {@link DataObjectIdentifier} view of this reference, if possible.
*
* @return A {@link DataObjectIdentifier}
* @throws UnsupportedOperationException if this reference is not compatible with {@link DataObjectIdentifier}
*/
@NonNull DataObjectIdentifier toIdentifier();
/**
* Returns {@code true} if this reference is composed solely of {@link ExactDataObjectStep}s.
*
* @implNote
* The default implementation returns {@code false} to simplify implementation hierarchy.
* @return {@code true} if this reference is composed solely of {@link ExactDataObjectStep}s
*/
default boolean isExact() {
return false;
}
/**
* Return a legacy {@link InstanceIdentifier} for this reference.
*
* @return An {@link InstanceIdentifier}.
*/
default @NonNull InstanceIdentifier toLegacy() {
return InstanceIdentifier.unsafeOf(ImmutableList.copyOf(steps()));
}
/**
* Return the steps of this reference. Returned {@link Iterable} does not support removals and contains one or more
* non-null ite,s.
*
* @return the steps of this reference
* @deprecated Use {@link #steps()} instead.
*/
@Deprecated(since = "14.0.0")
default @NonNull Iterable extends @NonNull DataObjectStep>> getPathArguments() {
return steps();
}
/**
* Returns {@code true} if this reference contains an {@link InexactDataObjectStep}s.
*
* @implSpec
* The default implementation returns {@code true} to simplify implementation hierarchy.
* @return {@code true} if this reference contains an {@link InexactDataObjectStep}
* @deprecated Use negated result of {@link #isExact()} instead
*/
@Deprecated(since = "14.0.0")
default boolean isWildcarded() {
return true;
}
}