Split out NotificationCodecContext.Prototype 78/106378/2
authorRobert Varga <robert.varga@pantheon.tech>
Sun, 4 Jun 2023 21:47:46 +0000 (23:47 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Sun, 4 Jun 2023 21:57:14 +0000 (23:57 +0200)
Notifications require a special context, split them out and guard
against re-instantiation.

Change-Id: I7eede21b2aeab92c02ae451a4c5e341361563bca
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/NotificationCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/SchemaRootCodecContext.java

index e446c7bdf28a1b717c6680664dfcb4c56b94c5b2..4fcbf16d5df08d10a8e1cb632b1301937cd9d585 100644 (file)
@@ -16,7 +16,6 @@ import org.eclipse.jdt.annotation.NonNull;
 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.CompositeRuntimeType;
-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.InstanceIdentifier.Item;
@@ -161,12 +160,6 @@ abstract sealed class DataContainerCodecPrototype<T extends RuntimeTypeContainer
         return new DataObjectCodecPrototype<>(bindingArg, createIdentifier(type), type, factory);
     }
 
-    static DataContainerCodecPrototype<NotificationRuntimeType> from(final Class<?> augClass,
-            final NotificationRuntimeType schema, final CodecContextFactory factory) {
-        return new DataObjectCodecPrototype<>(augClass, NodeIdentifier.create(schema.statement().argument()), schema,
-            factory);
-    }
-
     private static @NonNull NodeIdentifier createIdentifier(final CompositeRuntimeType type) {
         final Object arg = type.statement().argument();
         verify(arg instanceof QName, "Unexpected type %s argument %s", type, arg);
index b8cd98075dcbc10aa6592f7ba864db1334646943..9bae0af94c1d7ee0808ae55e72eaf5786686d41f 100644 (file)
@@ -39,6 +39,7 @@ import org.opendaylight.mdsal.binding.runtime.api.NotificationRuntimeType;
 import org.opendaylight.yangtools.yang.binding.BaseNotification;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.EventInstantAware;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -68,9 +69,9 @@ final class NotificationCodecContext<D extends DataObject & BaseNotification>
 
     private final MethodHandle eventProxy;
 
-    NotificationCodecContext(final Class<?> key, final NotificationRuntimeType schema,
+    NotificationCodecContext(final Class<?> notificationClass, final NotificationRuntimeType type,
             final CodecContextFactory factory) {
-        super(DataContainerCodecPrototype.from(key, schema, factory));
+        super(new Prototype<>(notificationClass, type, factory));
         final Class<D> bindingClass = getBindingClass();
 
         final Class<?> awareClass = CodecPackage.EVENT_AWARE.generateClass(factory().getLoader(), bindingClass,
@@ -121,6 +122,22 @@ final class NotificationCodecContext<D extends DataObject & BaseNotification>
         return deserialize(normalizedNode);
     }
 
+    /**
+     * Prototype for a {@code notiofication}. This class only exists because DataContainerCodecContext requires a
+     * prototype.
+     */
+    private static final class Prototype<D extends DataObject & BaseNotification>
+            extends DataObjectCodecPrototype<NotificationRuntimeType> {
+        Prototype(final Class<?> cls, final NotificationRuntimeType type, final CodecContextFactory factory) {
+            super(cls, NodeIdentifier.create(type.statement().argument()), type, factory);
+        }
+
+        @Override
+        DataContainerCodecContext<?, NotificationRuntimeType> createInstance() {
+            throw new UnsupportedOperationException("Should never be invoked");
+        }
+    }
+
     private enum ConstructorImplementation implements Implementation {
         INSTANCE;
 
index b190aad2b2377b61231fd774a7972f1dcdda6fb3..133c75f254de38a7b4743ab86588a8f396f3b37a 100644 (file)
@@ -114,14 +114,15 @@ final class SchemaRootCodecContext<D extends DataObject> extends DataContainerCo
         .build(new CacheLoader<Class<?>, NotificationCodecContext<?>>() {
             @Override
             public NotificationCodecContext<?> load(final Class<?> key) {
+                // FIXME: sharpen check to an Notification.class
                 checkArgument(key.isInterface(), "Supplied class must be interface.");
 
                 // TODO: we should be able to work with bindingChild() instead of schemaTreeChild() here
-                final QName qname = BindingReflections.findQName(key);
-                final RuntimeType child = getType().schemaTreeChild(qname);
-                checkArgument(child instanceof NotificationRuntimeType, "Supplied %s is not valid notification",
-                    key);
-                return new NotificationCodecContext<>(key, (NotificationRuntimeType) child, factory());
+                final var qname = BindingReflections.findQName(key);
+                if (getType().schemaTreeChild(qname) instanceof NotificationRuntimeType type) {
+                    return new NotificationCodecContext<>(key, type, factory());
+                }
+                throw new IllegalArgumentException("Supplied " + key + " is not valid notification");
             }
         });
 
@@ -214,10 +215,12 @@ final class SchemaRootCodecContext<D extends DataObject> extends DataContainerCo
         CacheBuilder.newBuilder().build(new CacheLoader<>() {
             @Override
             public NotificationCodecContext<?> load(final Absolute key) {
-                final Class<?> cls = factory().getRuntimeContext().getClassForSchema(key);
-                checkArgument(Notification.class.isAssignableFrom(cls), "Path %s does not represent a notification",
-                    key);
-                return getNotificationImpl(cls);
+                final var cls = factory().getRuntimeContext().getClassForSchema(key);
+                try {
+                    return getNotificationImpl(cls.asSubclass(Notification.class));
+                } catch (ClassCastException e) {
+                    throw new IllegalArgumentException("Path " + key + " does not represent a notification", e);
+                }
             }
         });