Hide CodecContextSupplier 42/109742/3
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 11 Jan 2024 12:05:53 +0000 (13:05 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 11 Jan 2024 13:25:21 +0000 (14:25 +0100)
Refactoring InstanceIdentifier.Item flushes out a problem with the class
hierarchy of ChoiceNodeContextPrototype.

Start off by refactoring CodecContextSupplier, introducing
LazyCodecContextSupplier base class.

JIRA: MDSAL-815
Change-Id: I79fe079d9fc4b0adf166c1a8b2561fb03a2f071f
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AbstractDataObjectCodecContext.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/CodecContextSupplier.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CodecDataObject.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/DataContainerCodecContext.java
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 [new file with mode: 0644]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ValueNodeCodecContext.java

index 6748f6bb979e4bfbec189f962593dcab835e97a2..0afa5e63e45a932d1ba14757198ffe58c21c7cda 100644 (file)
@@ -74,7 +74,7 @@ public abstract sealed class AbstractDataObjectCodecContext<D extends DataObject
         final var argType = arg.getType();
         final var context = childNonNull(pathChildPrototype(argType), argType,
             "Class %s is not valid child of %s", argType, getBindingClass())
-            .get();
+            .getCodecContext();
         if (context instanceof ChoiceCodecContext<?> choice) {
             choice.addYangPathArgument(arg, builder);
 
index 9e55f2da29a157b1e58fcbefdad02380f14f2c19..a7ec5fabb26744a05b1317d33d9097cc606f1e20 100644 (file)
@@ -238,7 +238,7 @@ final class ChoiceCodecContext<D extends DataObject> extends CommonDataObjectCod
             return null;
         }
         final var caze = byYangCaseChild.get(first.name());
-        return ((CaseCodecContext<D>) caze.get()).deserialize(data);
+        return ((CaseCodecContext<D>) caze.getCodecContext()).deserialize(data);
     }
 
     @Override
@@ -288,7 +288,8 @@ final class ChoiceCodecContext<D extends DataObject> extends CommonDataObjectCod
             }
         }
 
-        return childNonNull(result, type, "Class %s is not child of any cases for %s", type, bindingArg()).get();
+        return childNonNull(result, type, "Class %s is not child of any cases for %s", type, bindingArg())
+            .getCodecContext();
     }
 
     /**
index 1fa8b1688758cd28db8ddc0290edf1eef84a9141..c8eaea1eb78167f5cc2a08b283410b3b0d32124e 100644 (file)
@@ -7,16 +7,14 @@
  */
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
-import com.google.common.annotations.Beta;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 
 /**
  * Type capture of an entity producing NodeCodecContexts. Implementations are required to perform memoization. This
  * interface does not form API surface and is exposed only for generated code. It can change at any time.
  */
-@Beta
-@FunctionalInterface
 @NonNullByDefault
-public interface CodecContextSupplier {
-    CodecContext get();
+sealed interface CodecContextSupplier permits LazyCodecContextSupplier, ValueNodeCodecContext {
+
+    CodecContext getCodecContext();
 }
index 173ccccd44bb2d00e61194c9deb110c1e2fc5d62..a32e7ea3094eb8ad498349f388231385df1f1729 100644 (file)
@@ -82,7 +82,7 @@ public abstract class CodecDataObject<T extends DataObject> implements DataObjec
 
     protected final Object codecMember(final VarHandle handle, final CodecContextSupplier supplier) {
         final Object cached = handle.getAcquire(this);
-        return cached != null ? unmaskNull(cached) : loadMember(handle, supplier.get());
+        return cached != null ? unmaskNull(cached) : loadMember(handle, supplier.getCodecContext());
     }
 
     protected final @NonNull Object codecMemberOrEmpty(final @Nullable Object value,
index 24340e46527227816b59f5efb9a5d575a4d349f4..ec3a2ea64c5ae04ae74e0dc1d5148a9b714cadc1 100644 (file)
@@ -9,36 +9,18 @@ package org.opendaylight.mdsal.binding.dom.codec.impl;
 
 import static java.util.Objects.requireNonNull;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 
-abstract sealed class CommonDataObjectCodecPrototype<T extends CompositeRuntimeType> implements CodecContextSupplier
+abstract sealed class CommonDataObjectCodecPrototype<T extends CompositeRuntimeType>
+        extends LazyCodecContextSupplier<CommonDataObjectCodecContext<?, T>>
         permits AugmentationCodecPrototype, DataObjectCodecPrototype {
-    private static final VarHandle INSTANCE;
-
-    static {
-        try {
-            INSTANCE = MethodHandles.lookup().findVarHandle(CommonDataObjectCodecPrototype.class,
-                "instance", CommonDataObjectCodecContext.class);
-        } catch (NoSuchFieldException | IllegalAccessException e) {
-            throw new ExceptionInInitializerError(e);
-        }
-    }
-
     private final @NonNull T type;
     private final @NonNull CodecContextFactory factory;
     private final @NonNull Item<?> bindingArg;
 
-    // Accessed via INSTANCE
-    @SuppressWarnings("unused")
-    @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749")
-    private volatile CommonDataObjectCodecContext<?, T> instance;
-
     CommonDataObjectCodecPrototype(final Item<?> bindingArg, final T type, final CodecContextFactory factory) {
         this.bindingArg = requireNonNull(bindingArg);
         this.type = requireNonNull(type);
@@ -62,19 +44,4 @@ abstract sealed class CommonDataObjectCodecPrototype<T extends CompositeRuntimeT
     }
 
     abstract @NonNull NodeIdentifier getYangArg();
-
-    @Override
-    public final CommonDataObjectCodecContext<?, T> get() {
-        final var existing = (CommonDataObjectCodecContext<?, T>) INSTANCE.getAcquire(this);
-        return existing != null ? existing : loadInstance();
-    }
-
-    private @NonNull CommonDataObjectCodecContext<?, T> loadInstance() {
-        final var tmp = createInstance();
-        final var witness = (CommonDataObjectCodecContext<?, T>) INSTANCE.compareAndExchangeRelease(this, null, tmp);
-        return witness == null ? tmp : witness;
-    }
-
-    // This method must allow concurrent loading, i.e. nothing in it may have effects outside of the loaded object
-    abstract @NonNull CommonDataObjectCodecContext<?, T> createInstance();
 }
index 608445ea036289a0d4e1eeb62c18989f08dceda3..f6cf8b627615c1b475c0b36f28d79ce13621fa12 100644 (file)
@@ -96,7 +96,7 @@ final class DataContainerAnalysis<R extends CompositeRuntimeType> {
             // 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) {
-                final var choice = (ChoiceCodecContext<?>) childProto.get();
+                final var choice = (ChoiceCodecContext<?>) childProto.getCodecContext();
                 for (var cazeChild : choice.getCaseChildrenClasses()) {
                     byBindingArgClassBuilder.put(cazeChild, childProto);
                 }
index 67cbc1aa3b47a521cfdc929bd6156fa73a41f685..4dec5e68c35795b85817906898d0d9f09d065982 100644 (file)
@@ -108,7 +108,7 @@ abstract sealed class DataContainerCodecContext<D extends BindingObject & DataCo
         } else {
             supplier = null;
         }
-        return childNonNull(supplier, arg, "Argument %s is not valid child of %s", arg, getSchema()).get();
+        return childNonNull(supplier, arg, "Argument %s is not valid child of %s", arg, getSchema()).getCodecContext();
     }
 
     abstract @Nullable CodecContextSupplier yangChildSupplier(@NonNull NodeIdentifier arg);
@@ -150,7 +150,7 @@ abstract sealed class DataContainerCodecContext<D extends BindingObject & DataCo
     @Override
     public final <C extends DataObject> CommonDataObjectCodecContext<C, ?> streamChild(final Class<C> childClass) {
         final var childProto = streamChildPrototype(requireNonNull(childClass));
-        return childProto == null ? null : (CommonDataObjectCodecContext<C, ?>) childProto.get();
+        return childProto == null ? null : (CommonDataObjectCodecContext<C, ?>) childProto.getCodecContext();
     }
 
     abstract @Nullable CommonDataObjectCodecPrototype<?> streamChildPrototype(@NonNull Class<?> childClass);
index f076958cf33c1652e0161c21d59fcd563553ce89..1666ec8043c4dd3259f028856954b623f1be3a26 100644 (file)
@@ -297,7 +297,7 @@ public abstract sealed class DataObjectCodecContext<D extends DataObject, T exte
             final var bindingClass = entry.getKey();
             final var codecProto = augmentToPrototype.get(bindingClass);
             if (codecProto != null) {
-                final var bindingObj = codecProto.get().deserializeObject(entry.getValue().build());
+                final var bindingObj = codecProto.getCodecContext().deserializeObject(entry.getValue().build());
                 if (bindingObj != null) {
                     map.put(bindingClass, bindingObj);
                 }
diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LazyCodecContextSupplier.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LazyCodecContextSupplier.java
new file mode 100644 (file)
index 0000000..051bd3e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * Abstract base class for lazily-instantiated {@link CodecContextSupplier} instances.
+ *
+ * @param <C> {@link CodecContext} type
+ */
+public abstract sealed class LazyCodecContextSupplier<C extends CodecContext> implements CodecContextSupplier
+        permits CommonDataObjectCodecPrototype {
+    private static final VarHandle INSTANCE;
+
+    static {
+        try {
+            INSTANCE = MethodHandles.lookup().findVarHandle(LazyCodecContextSupplier.class, "instance",
+                CodecContext.class);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    // Accessed via INSTANCE
+    @SuppressWarnings("unused")
+    @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749")
+    private volatile C instance;
+
+    @Override
+    public final C getCodecContext() {
+        final var existing = (C) INSTANCE.getAcquire(this);
+        return existing != null ? existing : loadInstance();
+    }
+
+    private @NonNull C loadInstance() {
+        final var tmp = createInstance();
+        final var witness = (C) INSTANCE.compareAndExchangeRelease(this, null, tmp);
+        return witness == null ? tmp : witness;
+    }
+
+    // This method must allow concurrent loading, i.e. nothing in it may have effects outside of the loaded object
+    abstract @NonNull C createInstance();
+}
index 2a9c53326666ee607f0aae5d4c8c93e480302c99..311ec98e9cd3964d03a4ea4d2d916b282a220ea1 100644 (file)
@@ -53,7 +53,7 @@ abstract sealed class ValueNodeCodecContext extends CodecContext implements Code
     }
 
     @Override
-    public final CodecContext get() {
+    public final CodecContext getCodecContext() {
         return this;
     }