Refactor PathArgument to DataObjectStep
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / DataContainerCodecContext.java
index 838e55b4ebe4a82fe12b2e507e5c09768d124201..2848884b277148ce1a9343210324234ea3e7b4f6 100644 (file)
@@ -12,6 +12,7 @@ import static java.util.Objects.requireNonNull;
 import com.google.common.collect.ImmutableCollection;
 import com.google.common.collect.ImmutableSet;
 import edu.umd.cs.findbugs.annotations.CheckReturnValue;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
@@ -40,10 +41,11 @@ import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.BindingObject;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizationResultHolder;
@@ -60,9 +62,10 @@ import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-abstract sealed class DataContainerCodecContext<D extends BindingObject & DataContainer, T extends CompositeRuntimeType>
+abstract sealed class DataContainerCodecContext<D extends DataContainer, R extends CompositeRuntimeType,
+        P extends DataContainerPrototype<?, R>>
         extends CodecContext implements BindingDataContainerCodecTreeNode<D>
-        permits CommonDataObjectCodecContext {
+        permits ChoiceCodecContext, CommonDataObjectCodecContext {
     private static final Logger LOG = LoggerFactory.getLogger(DataContainerCodecContext.class);
     private static final VarHandle EVENT_STREAM_SERIALIZER;
 
@@ -75,49 +78,73 @@ abstract sealed class DataContainerCodecContext<D extends BindingObject & DataCo
         }
     }
 
+    private final @NonNull P prototype;
     private final @NonNull ChildAddressabilitySummary childAddressabilitySummary;
 
     // Accessed via a VarHandle
     @SuppressWarnings("unused")
+    @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749")
     private volatile DataContainerSerializer eventStreamSerializer;
 
-    DataContainerCodecContext(final T type) {
-        childAddressabilitySummary = computeChildAddressabilitySummary(type.statement());
+    DataContainerCodecContext(final P prototype) {
+        this.prototype = requireNonNull(prototype);
+        childAddressabilitySummary = computeChildAddressabilitySummary(prototype.runtimeType().statement());
     }
 
-    @Override
-    public final ChildAddressabilitySummary getChildAddressabilitySummary() {
-        return childAddressabilitySummary;
+    final @NonNull P prototype() {
+        return prototype;
     }
 
-    protected abstract @NonNull CodecContextFactory factory();
+    @Override
+    @SuppressWarnings("unchecked")
+    public final Class<D> getBindingClass() {
+        return (Class<D>) prototype().javaClass();
+    }
 
-    protected abstract @NonNull T type();
+    // overridden in AugmentationCodecContext
+    @Override
+    protected NodeIdentifier getDomPathArgument() {
+        return prototype.yangArg();
+    }
 
     @Override
-    public abstract CodecContext yangPathArgumentChild(YangInstanceIdentifier.PathArgument arg);
+    public final ChildAddressabilitySummary getChildAddressabilitySummary() {
+        return childAddressabilitySummary;
+    }
 
+    // Non-final for ChoiceCodecContext
     @Override
-    public CommonDataObjectCodecContext<?, ?> bindingPathArgumentChild(final PathArgument arg,
-            final List<YangInstanceIdentifier.PathArgument> builder) {
-        final var child = getStreamChild(arg.getType());
-        child.addYangPathArgument(arg, builder);
-        return child;
+    public CodecContext yangPathArgumentChild(final PathArgument arg) {
+        CodecContextSupplier supplier;
+        if (arg instanceof NodeIdentifier nodeId) {
+            supplier = yangChildSupplier(nodeId);
+        } else if (arg instanceof NodeIdentifierWithPredicates nip) {
+            supplier = yangChildSupplier(new NodeIdentifier(nip.getNodeType()));
+        } else {
+            supplier = null;
+        }
+        return childNonNull(supplier, arg, "Argument %s is not valid child of %s", arg, getSchema()).getCodecContext();
     }
 
+    abstract @Nullable CodecContextSupplier yangChildSupplier(@NonNull NodeIdentifier arg);
+
+    @Override
+    public abstract CommonDataObjectCodecContext<?, ?> bindingPathArgumentChild(DataObjectStep<?> step,
+        List<PathArgument> builder);
+
     /**
      * Serializes supplied Binding Path Argument and adds all necessary YANG instance identifiers to supplied list.
      *
-     * @param arg Binding Path Argument
+     * @param step Binding Path Argument
      * @param builder DOM Path argument.
      */
-    final void addYangPathArgument(final PathArgument arg, final List<YangInstanceIdentifier.PathArgument> builder) {
+    final void addYangPathArgument(final DataObjectStep<?> step, final List<PathArgument> builder) {
         if (builder != null) {
-            addYangPathArgument(builder, arg);
+            addYangPathArgument(builder, step);
         }
     }
 
-    void addYangPathArgument(final @NonNull List<YangInstanceIdentifier.PathArgument> builder, final PathArgument arg) {
+    void addYangPathArgument(final @NonNull List<PathArgument> builder, final DataObjectStep<?> step) {
         final var yangArg = getDomPathArgument();
         if (yangArg != null) {
             builder.add(yangArg);
@@ -125,34 +152,34 @@ abstract sealed class DataContainerCodecContext<D extends BindingObject & DataCo
     }
 
     @Override
-    public final <C extends DataObject> CommonDataObjectCodecContext<C, ?> getStreamChild(final Class<C> childClass) {
+    public final <C extends DataObject> DataContainerCodecContext<C, ?, ?> getStreamChild(final Class<C> childClass) {
         return childNonNull(streamChild(childClass), childClass,
             "Child %s is not valid child of %s", getBindingClass(), childClass);
     }
 
     @SuppressWarnings("unchecked")
     @Override
-    public final <C extends DataObject> CommonDataObjectCodecContext<C, ?> streamChild(final Class<C> childClass) {
+    public final <C extends DataObject> DataContainerCodecContext<C, ?, ?> streamChild(final Class<C> childClass) {
         final var childProto = streamChildPrototype(requireNonNull(childClass));
-        return childProto == null ? null : (CommonDataObjectCodecContext<C, ?>) childProto.get();
+        return childProto == null ? null : (DataContainerCodecContext<C, ?, ?>) childProto.getCodecContext();
     }
 
-    abstract @Nullable CommonDataObjectCodecPrototype<?> streamChildPrototype(@NonNull Class<?> childClass);
+    abstract @Nullable DataContainerPrototype<?, ?> streamChildPrototype(@NonNull Class<?> childClass);
 
     @Override
     public String toString() {
         return getClass().getSimpleName() + " [" + getBindingClass() + "]";
     }
 
-    static final <T extends DataObject, C extends DataContainerCodecContext<T, ?> & BindingNormalizedNodeCodec<T>>
+    static final <T extends DataObject, C extends DataContainerCodecContext<T, ?, ?> & BindingNormalizedNodeCodec<T>>
             @NonNull BindingNormalizedNodeCachingCodec<T> createCachingCodec(final C context,
                 final ImmutableCollection<Class<? extends BindingObject>> cacheSpecifier) {
         return cacheSpecifier.isEmpty() ? new NonCachingCodec<>(context)
             : new CachingNormalizedNodeCodec<>(context, ImmutableSet.copyOf(cacheSpecifier));
     }
 
-    protected final <V> @NonNull V childNonNull(final @Nullable V nullable,
-            final YangInstanceIdentifier.PathArgument child, final String message, final Object... args) {
+    protected final <V> @NonNull V childNonNull(final @Nullable V nullable, final PathArgument child,
+            final String message, final Object... args) {
         if (nullable == null) {
             throw childNullException(child.getNodeType(), message, args);
         }
@@ -177,8 +204,8 @@ abstract sealed class DataContainerCodecContext<D extends BindingObject & DataCo
 
     @CheckReturnValue
     private IllegalArgumentException childNullException(final QName child, final String message, final Object... args) {
-        final QNameModule module = child.getModule();
-        if (!factory().getRuntimeContext().getEffectiveModelContext().findModule(module).isPresent()) {
+        final var module = child.getModule();
+        if (!prototype().contextFactory().getRuntimeContext().modelContext().findModule(module).isPresent()) {
             return new MissingSchemaException("Module " + module + " is not present in current schema context.");
         }
         return new IncorrectNestingException(message, args);
@@ -187,7 +214,7 @@ abstract sealed class DataContainerCodecContext<D extends BindingObject & DataCo
     @CheckReturnValue
     private @NonNull IllegalArgumentException childNullException(final Class<?> childClass, final String message,
             final Object... args) {
-        return childNullException(factory().getRuntimeContext(), childClass, message, args);
+        return childNullException(prototype().contextFactory().getRuntimeContext(), childClass, message, args);
     }
 
     @CheckReturnValue
@@ -220,7 +247,7 @@ abstract sealed class DataContainerCodecContext<D extends BindingObject & DataCo
 
     // Split out to aid inlining
     private DataContainerSerializer loadEventStreamSerializer() {
-        final DataContainerSerializer loaded = factory().getEventStreamSerializer(getBindingClass());
+        final DataContainerSerializer loaded = prototype().contextFactory().getEventStreamSerializer(getBindingClass());
         final Object witness = EVENT_STREAM_SERIALIZER.compareAndExchangeRelease(this, null, loaded);
         return witness == null ? loaded : (DataContainerSerializer) witness;
     }