Separate out DataContainerPrototype 45/109745/1
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 11 Jan 2024 15:38:56 +0000 (16:38 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 11 Jan 2024 16:22:14 +0000 (17:22 +0100)
We have CommonDataObjectCodecPrototype defining strict prerequisites
while providing awefully little in terms of API worth.

Split out DataContainerPrototype, which exposes a typed javaClass() and
the corresponding runtimeType().

JIRA: MDSAL-815
Change-Id: Icaca2603e3b946764ff9d4157ab04be95bd4dde2
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AugmentationCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CaseCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerAnalysis.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerPrototype.java [new file with mode: 0644]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LazyCodecContextSupplier.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/MapCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/MapCodecPrototype.java

index 2d61c85456e952c376ad49e3fc02e5f31b169a30..9401a0e2f62fa06035d9a148b77099c4c79b63db 100644 (file)
@@ -37,8 +37,8 @@ final class AugmentationCodecContext<D extends DataObject & Augmentation<?>>
             final DataContainerAnalysis<AugmentRuntimeType> analysis) {
         super(prototype, analysis);
 
-        final var bindingClass = CodecDataObjectGenerator.generate(prototype.getFactory().getLoader(),
-            prototype.getBindingClass(), analysis.leafContexts, analysis.daoProperties, null);
+        final var bindingClass = CodecDataObjectGenerator.generate(prototype.contextFactory().getLoader(),
+            prototype.javaClass(), analysis.leafContexts, analysis.daoProperties, null);
 
         final MethodHandle ctor;
         try {
index fb3a59b1246f9b4370682e541d1b74f1b64cb854..11d59e47a0947a6c535df690f574c92d9aac6f6d 100644 (file)
@@ -19,7 +19,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
 final class CaseCodecContext<D extends DataObject> extends DataObjectCodecContext<D, CaseRuntimeType> {
     CaseCodecContext(final CaseCodecPrototype prototype) {
-        super(prototype, CodecItemFactory.of(prototype.getBindingClass()));
+        super(prototype, CodecItemFactory.of(prototype.javaClass()));
     }
 
     @Override
index a7ec5fabb26744a05b1317d33d9097cc606f1e20..810dfdca652c28b0204fad333834cc732e06985d 100644 (file)
@@ -116,8 +116,8 @@ final class ChoiceCodecContext<D extends DataObject> extends CommonDataObjectCod
             .<Class<?>, CommonDataObjectCodecPrototype<?>>build();
 
         // Load case statements valid in this choice and keep track of their names
-        final var choiceType = prototype.getType();
-        final var factory = prototype.getFactory();
+        final var choiceType = prototype.runtimeType();
+        final var factory = prototype.contextFactory();
         final var localCases = new HashSet<JavaTypeName>();
         for (var caseType : choiceType.validCaseChildren()) {
             @SuppressWarnings("unchecked")
@@ -148,7 +148,7 @@ final class ChoiceCodecContext<D extends DataObject> extends CommonDataObjectCod
             if (cases.size() != 1) {
                 // Sort all possibilities by their FQCN to retain semi-predictable results
                 final var list = new ArrayList<>(entry.getValue());
-                list.sort(Comparator.comparing(proto -> proto.getBindingClass().getCanonicalName()));
+                list.sort(Comparator.comparing(proto -> proto.javaClass().getCanonicalName()));
                 ambiguousByCaseBuilder.putAll(entry.getKey(), list);
             } else {
                 unambiguousByCaseBuilder.put(entry.getKey(), cases.iterator().next());
@@ -282,8 +282,8 @@ final class ChoiceCodecContext<D extends DataObject> extends CommonDataObjectCod
                         Ambiguous reference {} to child of {} resolved to {}, the first case in {} This mapping is \
                         not guaranteed to be stable and is subject to variations based on runtime circumstances. \
                         Please see the stack trace for hints about the source of ambiguity.""",
-                        type, bindingArg(), result.getBindingClass(),
-                        Lists.transform(inexact, CommonDataObjectCodecPrototype::getBindingClass), new Throwable());
+                        type, bindingArg(), result.javaClass(),
+                        Lists.transform(inexact, CommonDataObjectCodecPrototype::javaClass), new Throwable());
                 }
             }
         }
index 5c5fa04e63a9ee763bf1d9088375efaade44ac9d..cae761a9bb2db286a26641e80c73ac7e291fb065 100644 (file)
@@ -26,24 +26,24 @@ abstract sealed class CommonDataObjectCodecContext<D extends DataObject, T exten
     final @NonNull CommonDataObjectCodecPrototype<T> prototype;
 
     CommonDataObjectCodecContext(final CommonDataObjectCodecPrototype<T> prototype) {
-        super(prototype.getType());
+        super(prototype.runtimeType());
         this.prototype = requireNonNull(prototype);
     }
 
     @SuppressWarnings("unchecked")
     @Override
     public final Class<D> getBindingClass() {
-        return Class.class.cast(prototype.getBindingClass());
+        return Class.class.cast(prototype.javaClass());
     }
 
     @Override
     protected final CodecContextFactory factory() {
-        return prototype.getFactory();
+        return prototype.contextFactory();
     }
 
     @Override
     protected final T type() {
-        return prototype.getType();
+        return prototype.runtimeType();
     }
 
     @Override
index ec3a2ea64c5ae04ae74e0dc1d5148a9b714cadc1..49b863b0061b43ca258ba98311c0a6cb065ccaf0 100644 (file)
@@ -11,31 +11,27 @@ import static java.util.Objects.requireNonNull;
 
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
+import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 
-abstract sealed class CommonDataObjectCodecPrototype<T extends CompositeRuntimeType>
-        extends LazyCodecContextSupplier<CommonDataObjectCodecContext<?, T>>
+/**
+ * Common superclass for {@link DataObjectCodecPrototype} and {@link AugmentationCodecPrototype}.
+ *
+ * @param <R> {@link CompositeRuntimeType} type
+ */
+abstract sealed class CommonDataObjectCodecPrototype<R extends CompositeRuntimeType>
+        extends DataContainerPrototype<CommonDataObjectCodecContext<?, R>, R>
         permits AugmentationCodecPrototype, DataObjectCodecPrototype {
-    private final @NonNull T type;
-    private final @NonNull CodecContextFactory factory;
     private final @NonNull Item<?> bindingArg;
 
-    CommonDataObjectCodecPrototype(final Item<?> bindingArg, final T type, final CodecContextFactory factory) {
+    CommonDataObjectCodecPrototype(final Item<?> bindingArg, final R runtimeType, final CodecContextFactory factory) {
+        super(factory, runtimeType);
         this.bindingArg = requireNonNull(bindingArg);
-        this.type = requireNonNull(type);
-        this.factory = requireNonNull(factory);
-    }
-
-    final @NonNull T getType() {
-        return type;
-    }
-
-    final @NonNull CodecContextFactory getFactory() {
-        return factory;
     }
 
-    final @NonNull Class<?> getBindingClass() {
+    @Override
+    final Class<? extends DataObject> javaClass() {
         return bindingArg.getType();
     }
 
index f6cf8b627615c1b475c0b36f28d79ce13621fa12..cbb3a974196eb3e9289d3ab719c19eb36dfb7a1c 100644 (file)
@@ -52,7 +52,7 @@ final class DataContainerAnalysis<R extends CompositeRuntimeType> {
     final @NonNull ImmutableMap<Class<?>, PropertyInfo> daoProperties;
 
     DataContainerAnalysis(final CommonDataObjectCodecPrototype<R> prototype, final CodecItemFactory itemFactory) {
-        this(prototype.getBindingClass(), prototype.getType(), prototype.getFactory(), itemFactory);
+        this(prototype.javaClass(), prototype.runtimeType(), prototype.contextFactory(), itemFactory);
     }
 
     DataContainerAnalysis(final Class<?> bindingClass, final R runtimeType, final CodecContextFactory factory,
@@ -90,12 +90,12 @@ final class DataContainerAnalysis<R extends CompositeRuntimeType> {
             daoPropertiesBuilder.put(retClass, new PropertyInfo.Getter(method));
 
             final var childProto = getChildPrototype(runtimeType, factory, itemFactory, retClass);
-            byStreamClassBuilder.put(childProto.getBindingClass(), childProto);
+            byStreamClassBuilder.put(childProto.javaClass(), childProto);
             byYangBuilder.put(childProto.getYangArg(), childProto);
 
             // FIXME: It really feels like we should be specializing DataContainerCodecPrototype so as to ditch
             //        createInstance() and then we could do an instanceof check instead.
-            if (childProto.getType() instanceof ChoiceRuntimeType) {
+            if (childProto.runtimeType() instanceof ChoiceRuntimeType) {
                 final var choice = (ChoiceCodecContext<?>) childProto.getCodecContext();
                 for (var cazeChild : choice.getCaseChildrenClasses()) {
                     byBindingArgClassBuilder.put(cazeChild, childProto);
diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerPrototype.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerPrototype.java
new file mode 100644 (file)
index 0000000..9fbc08e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.mdsal.binding.dom.codec.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+
+/**
+ * A prototype for codecs dealing with {@link DataContainer}s.
+ *
+ * @param <C> {@link CodecContext} type
+ * @param <R> {@link CompositeRuntimeType} type
+ */
+abstract sealed class DataContainerPrototype<C extends CodecContext, R extends CompositeRuntimeType>
+        extends LazyCodecContextSupplier<C> permits CommonDataObjectCodecPrototype {
+    private final @NonNull CodecContextFactory contextFactory;
+    private final @NonNull R runtimeType;
+
+    DataContainerPrototype(final CodecContextFactory contextFactory, final R runtimeType) {
+        this.contextFactory = requireNonNull(contextFactory);
+        this.runtimeType = requireNonNull(runtimeType);
+    }
+
+    /**
+     * Return the {@link CodecContextFactory} associated with this prototype.
+     *
+     * @return the context factory associated with this prototype
+     */
+    final @NonNull CodecContextFactory contextFactory() {
+        return contextFactory;
+    }
+
+    /**
+     * Return associated run-time type.
+     *
+     * @return associated run-time type
+     */
+    final @NonNull R runtimeType() {
+        return runtimeType;
+    }
+
+    /**
+     * Return the generated binding class this prototype corresponds to.
+     *
+     * @return the generated binding class this prototype corresponds to
+     */
+    abstract @NonNull Class<? extends DataContainer> javaClass();
+}
index 1666ec8043c4dd3259f028856954b623f1be3a26..a1a24dda503701429d434b22c82c21bd0184ce29 100644 (file)
@@ -107,7 +107,7 @@ public abstract sealed class DataObjectCodecContext<D extends DataObject, T exte
         final List<AugmentRuntimeType> possibleAugmentations;
         if (Augmentable.class.isAssignableFrom(bindingClass)) {
             // Verify we have the appropriate backing runtimeType
-            final var runtimeType = prototype.getType();
+            final var runtimeType = prototype.runtimeType();
             if (!(runtimeType instanceof AugmentableRuntimeType augmentableRuntimeType)) {
                 throw new VerifyException(
                     "Unexpected type %s backing augmenable %s".formatted(runtimeType, bindingClass));
@@ -138,7 +138,7 @@ public abstract sealed class DataObjectCodecContext<D extends DataObject, T exte
         for (var augment : possibleAugmentations) {
             final var augProto = loadAugmentPrototype(augment);
             if (augProto != null) {
-                final var augBindingClass = augProto.getBindingClass();
+                final var augBindingClass = augProto.javaClass();
                 for (var childPath : augProto.getChildArgs()) {
                     augPathToBinding.putIfAbsent(childPath, augBindingClass);
                 }
@@ -201,8 +201,8 @@ public abstract sealed class DataObjectCodecContext<D extends DataObject, T exte
         // context would load.
         if (getBindingClass().equals(augTarget) && belongsToRuntimeContext(childClass)) {
             for (var realChild : augmentToPrototype.values()) {
-                if (Augmentation.class.isAssignableFrom(realChild.getBindingClass())
-                        && isSubstitutionFor(childClass, realChild.getBindingClass())) {
+                final var realClass = realChild.javaClass();
+                if (Augmentation.class.isAssignableFrom(realClass) && isSubstitutionFor(childClass, realClass)) {
                     return cacheMismatched(oldMismatched, childClass, realChild);
                 }
             }
index 051bd3edf7bc5bd2feda6aa49c21004c440cbd22..a4f13f4835c05346a866eb714f21f3103b4fb72a 100644 (file)
@@ -17,8 +17,10 @@ import org.eclipse.jdt.annotation.NonNull;
  *
  * @param <C> {@link CodecContext} type
  */
-public abstract sealed class LazyCodecContextSupplier<C extends CodecContext> implements CodecContextSupplier
-        permits CommonDataObjectCodecPrototype {
+abstract sealed class LazyCodecContextSupplier<C extends CodecContext> implements CodecContextSupplier
+        // Note: while we could merge this class into DataContainerCodecPrototype, we want to keep the lazy-loading part
+        //       separate in case we need to non-DataContainer contexts.
+        permits DataContainerPrototype {
     private static final VarHandle INSTANCE;
 
     static {
index b91d8af2858f3cde42b21074a8a1274f60f9bcc1..9b497fce4b34e00e4bceb72453e56e4e7c1b7504 100644 (file)
@@ -62,7 +62,7 @@ abstract sealed class MapCodecContext<I extends Key<D>, D extends DataObject & K
     }
 
     static @NonNull MapCodecContext<?, ?> of(final MapCodecPrototype prototype) {
-        final var bindingClass = prototype.getBindingClass();
+        final var bindingClass = prototype.javaClass();
         final Method keyMethod;
         try {
             keyMethod = bindingClass.getMethod(Naming.KEY_AWARE_KEY_NAME);
@@ -70,8 +70,8 @@ abstract sealed class MapCodecContext<I extends Key<D>, D extends DataObject & K
             throw new IllegalStateException("Required method not available", e);
         }
 
-        final var type = prototype.getType();
-        final var codec = prototype.getFactory().getPathArgumentCodec(bindingClass, type);
+        final var type = prototype.runtimeType();
+        final var codec = prototype.contextFactory().getPathArgumentCodec(bindingClass, type);
 
         return type.statement().ordering() == Ordering.SYSTEM ? new Unordered<>(prototype, keyMethod, codec)
             : new Ordered<>(prototype, keyMethod, codec);
index 1ee41f77eb16b97f8d63087ba65d0f4ea65a2c98..58080631b9ae11949814a0ab4b54799333afc08b 100644 (file)
@@ -19,7 +19,7 @@ import org.opendaylight.yangtools.yang.binding.KeyAware;
 final class MapCodecPrototype extends ListCodecPrototype {
     MapCodecPrototype(final Item<?> item, final ListRuntimeType type, final CodecContextFactory factory) {
         super(item, type, factory);
-        final var clazz = getBindingClass();
+        final var clazz = javaClass();
         checkArgument(KeyAware.class.isAssignableFrom(clazz), "%s is not KeyAware", clazz);
     }