package org.opendaylight.mdsal.binding.dom.codec.impl;
import static com.google.common.base.Verify.verify;
+import static java.util.Objects.requireNonNull;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode.ChildAddressabilitySummary;
+import org.opendaylight.mdsal.binding.dom.codec.api.CommonDataObjectCodecTreeNode.ChildAddressabilitySummary;
import org.opendaylight.mdsal.binding.dom.codec.impl.NodeCodecContext.CodecContextFactory;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeTypes;
-import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ContainerLikeRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ContainerRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.NotificationRuntimeType;
import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
import org.opendaylight.mdsal.binding.runtime.api.RuntimeTypeContainer;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.DataRoot;
-import org.opendaylight.yangtools.yang.binding.Identifiable;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.model.api.AnydataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.stmt.PresenceEffectiveStatement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-final class DataContainerCodecPrototype<T extends RuntimeTypeContainer> implements NodeContextSupplier {
+abstract sealed class DataContainerCodecPrototype<T extends RuntimeTypeContainer> implements NodeContextSupplier
+ permits AugmentationCodecPrototype, DataObjectCodecPrototype {
private static final Logger LOG = LoggerFactory.getLogger(DataContainerCodecPrototype.class);
private static final VarHandle INSTANCE;
}
}
- private final T type;
- private final QNameModule namespace;
- private final CodecContextFactory factory;
- private final Item<?> bindingArg;
- private final PathArgument yangArg;
- private final ChildAddressabilitySummary childAddressabilitySummary;
+ private final @NonNull T type;
+ private final @NonNull QNameModule namespace;
+ private final @NonNull CodecContextFactory factory;
+ private final @NonNull Item<?> bindingArg;
+ private final @NonNull ChildAddressabilitySummary childAddressabilitySummary;
+
+ // multiple paths represent augmentation wrapper
+ // FIXME: this means it is either this or 'childArgs'
// Accessed via INSTANCE
@SuppressWarnings("unused")
private volatile DataContainerCodecContext<?, T> instance;
- @SuppressWarnings("unchecked")
- private DataContainerCodecPrototype(final Class<?> cls, final PathArgument arg, final T type,
- final CodecContextFactory factory) {
- this(Item.of((Class<? extends DataObject>) cls), arg, type, factory);
- }
-
- private DataContainerCodecPrototype(final Item<?> bindingArg, final PathArgument arg, final T type,
+ DataContainerCodecPrototype(final Item<?> bindingArg, final QNameModule namespace, final T type,
final CodecContextFactory factory) {
- this.bindingArg = bindingArg;
- this.yangArg = arg;
- this.type = type;
- this.factory = factory;
+ this.bindingArg = requireNonNull(bindingArg);
+ this.namespace = requireNonNull(namespace);
+ this.type = requireNonNull(type);
+ this.factory = requireNonNull(factory);
- if (arg instanceof AugmentationIdentifier augId) {
- final var childNames = augId.getPossibleChildNames();
- verify(!childNames.isEmpty(), "Unexpected empty identifier for %s", type);
- this.namespace = childNames.iterator().next().getModule();
- } else {
- this.namespace = arg.getNodeType().getModule();
- }
-
- this.childAddressabilitySummary = type instanceof RuntimeType
- ? computeChildAddressabilitySummary(((RuntimeType) type).statement())
+ childAddressabilitySummary = type instanceof RuntimeType runtimeType
+ ? computeChildAddressabilitySummary(runtimeType.statement())
// BindingRuntimeTypes, does not matter
: ChildAddressabilitySummary.MIXED;
}
- private static ChildAddressabilitySummary computeChildAddressabilitySummary(final Object nodeSchema) {
+ private static @NonNull ChildAddressabilitySummary computeChildAddressabilitySummary(final Object nodeSchema) {
// FIXME: rework this to work on EffectiveStatements
if (nodeSchema instanceof DataNodeContainer contaner) {
boolean haveAddressable = false;
return ChildAddressabilitySummary.UNADDRESSABLE;
}
- private static ChildAddressabilitySummary computeChildAddressabilitySummary(final ChoiceSchemaNode choice) {
+ private static @NonNull ChildAddressabilitySummary computeChildAddressabilitySummary(
+ final ChoiceSchemaNode choice) {
boolean haveAddressable = false;
boolean haveUnaddressable = false;
for (CaseSchemaNode child : choice.getCases()) {
return haveUnaddressable ? ChildAddressabilitySummary.MIXED : ChildAddressabilitySummary.ADDRESSABLE;
}
- static DataContainerCodecPrototype<BindingRuntimeTypes> rootPrototype(final CodecContextFactory factory) {
- return new DataContainerCodecPrototype<>(DataRoot.class, NodeIdentifier.create(SchemaContext.NAME),
- factory.getRuntimeContext().getTypes(), factory);
- }
-
static <T extends CompositeRuntimeType> DataContainerCodecPrototype<T> from(final Class<?> cls, final T type,
final CodecContextFactory factory) {
- return new DataContainerCodecPrototype<>(cls, createIdentifier(type), type, factory);
+ return new DataObjectCodecPrototype<>(cls, createIdentifier(type), type, factory);
}
static <T extends CompositeRuntimeType> DataContainerCodecPrototype<T> from(final Item<?> bindingArg, final T type,
final CodecContextFactory factory) {
- return new DataContainerCodecPrototype<>(bindingArg, createIdentifier(type), type, factory);
- }
-
- static DataContainerCodecPrototype<AugmentRuntimeType> from(final Class<?> augClass,
- final AugmentationIdentifier arg, final AugmentRuntimeType schema, final CodecContextFactory factory) {
- return new DataContainerCodecPrototype<>(augClass, arg, schema, factory);
- }
-
- static DataContainerCodecPrototype<NotificationRuntimeType> from(final Class<?> augClass,
- final NotificationRuntimeType schema, final CodecContextFactory factory) {
- final PathArgument arg = NodeIdentifier.create(schema.statement().argument());
- return new DataContainerCodecPrototype<>(augClass, arg, schema, factory);
+ return new DataObjectCodecPrototype<>(bindingArg, createIdentifier(type), type, factory);
}
private static @NonNull NodeIdentifier createIdentifier(final CompositeRuntimeType type) {
return NodeIdentifier.create((QName) arg);
}
- @NonNull T getType() {
+ final @NonNull T getType() {
return type;
}
- ChildAddressabilitySummary getChildAddressabilitySummary() {
+ final @NonNull ChildAddressabilitySummary getChildAddressabilitySummary() {
return childAddressabilitySummary;
}
- QNameModule getNamespace() {
+ final @NonNull QNameModule getNamespace() {
return namespace;
}
- CodecContextFactory getFactory() {
+ final @NonNull CodecContextFactory getFactory() {
return factory;
}
- Class<?> getBindingClass() {
+ final @NonNull Class<?> getBindingClass() {
return bindingArg.getType();
}
- Item<?> getBindingArg() {
+ final @NonNull Item<?> getBindingArg() {
return bindingArg;
}
- PathArgument getYangArg() {
- return yangArg;
- }
+ abstract @NonNull NodeIdentifier getYangArg();
@Override
- public DataContainerCodecContext<?, T> get() {
- final DataContainerCodecContext<?, T> existing = (DataContainerCodecContext<?, T>) INSTANCE.getAcquire(this);
+ public final DataContainerCodecContext<?, T> get() {
+ final var existing = (DataContainerCodecContext<?, T>) INSTANCE.getAcquire(this);
return existing != null ? existing : loadInstance();
}
+ @SuppressWarnings("unchecked")
+ final <R extends CompositeRuntimeType> DataObjectCodecContext<?, R> getDataObject() {
+ final var context = get();
+ verify(context instanceof DataObjectCodecContext, "Unexpected instance %s", context);
+ return (DataObjectCodecContext<?, R>) context;
+ }
+
private @NonNull DataContainerCodecContext<?, T> loadInstance() {
final var tmp = createInstance();
final var witness = (DataContainerCodecContext<?, T>) INSTANCE.compareAndExchangeRelease(this, null, tmp);
return witness == null ? tmp : witness;
}
- @SuppressWarnings({ "rawtypes", "unchecked" })
// This method must allow concurrent loading, i.e. nothing in it may have effects outside of the loaded object
- private @NonNull DataContainerCodecContext<?, T> createInstance() {
- // FIXME: make protected abstract
- if (type instanceof ContainerLikeRuntimeType containerLike) {
- if (containerLike instanceof ContainerRuntimeType container
- && container.statement().findFirstEffectiveSubstatement(PresenceEffectiveStatement.class).isEmpty()) {
- return new NonPresenceContainerNodeCodecContext(this);
- }
- return new ContainerNodeCodecContext(this);
- } else if (type instanceof ListRuntimeType) {
- return Identifiable.class.isAssignableFrom(getBindingClass())
- ? KeyedListNodeCodecContext.create((DataContainerCodecPrototype<ListRuntimeType>) this)
- : new ListNodeCodecContext(this);
- } else if (type instanceof ChoiceRuntimeType) {
- return new ChoiceNodeCodecContext(this);
- } else if (type instanceof AugmentRuntimeType) {
- return new AugmentationNodeContext(this);
- } else if (type instanceof CaseRuntimeType) {
- return new CaseNodeCodecContext(this);
- }
- throw new IllegalArgumentException("Unsupported type " + getBindingClass() + " " + type);
- }
+ abstract @NonNull DataContainerCodecContext<?, T> createInstance();
}