Split out NotificationCodecContext.Prototype
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / DataContainerCodecPrototype.java
index e9a8c119c7b9dd88382454b41d15650821a99bfb..4fcbf16d5df08d10a8e1cb632b1301937cd9d585 100644 (file)
@@ -8,32 +8,20 @@
 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;
@@ -43,13 +31,12 @@ import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 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;
@@ -63,45 +50,33 @@ final class DataContainerCodecPrototype<T extends RuntimeTypeContainer> implemen
         }
     }
 
-    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;
@@ -147,7 +122,8 @@ final class DataContainerCodecPrototype<T extends RuntimeTypeContainer> implemen
         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()) {
@@ -174,30 +150,14 @@ final class DataContainerCodecPrototype<T extends RuntimeTypeContainer> implemen
         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) {
@@ -206,67 +166,51 @@ final class DataContainerCodecPrototype<T extends RuntimeTypeContainer> implemen
         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();
 }