Bump upstreams
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / AugmentableCodecDataObject.java
index 43edeadb86a597cab8533ecf1a868b759533e87a..6a74a24661bd80ba433b8f13ea1305ff893f67b2 100644 (file)
@@ -9,21 +9,17 @@ package org.opendaylight.mdsal.binding.dom.codec.impl;
 
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.base.MoreObjects.ToStringHelper;
-import com.google.common.collect.ImmutableClassToInstanceMap;
+import com.google.common.collect.ImmutableMap;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.mdsal.binding.dom.codec.util.AugmentationReader;
-import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
 import org.opendaylight.yangtools.yang.binding.Augmentable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.AugmentationHolder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 
 /**
  * A base class for {@link DataObject}s which are also {@link Augmentable}, backed by {@link DataObjectCodecContext}.
@@ -33,81 +29,70 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
  * @param <T> DataObject type
  */
 public abstract class AugmentableCodecDataObject<T extends DataObject & Augmentable<T>>
-        extends CodecDataObject<T> implements Augmentable<T>, AugmentationHolder<T> {
-    private final @NonNull DataObjectCodecContext<T, ?> context;
+        extends CodecDataObject<T> implements Augmentable<T> {
+    private static final VarHandle CACHED_AUGMENTATIONS;
 
-    @SuppressWarnings("rawtypes")
-    private static final AtomicReferenceFieldUpdater<AugmentableCodecDataObject, ImmutableClassToInstanceMap>
-            CACHED_AUGMENTATIONS_UPDATER = AtomicReferenceFieldUpdater.newUpdater(AugmentableCodecDataObject.class,
-                ImmutableClassToInstanceMap.class, "cachedAugmentations");
-    private volatile ImmutableClassToInstanceMap<Augmentation<T>> cachedAugmentations;
+    static {
+        try {
+            CACHED_AUGMENTATIONS = MethodHandles.lookup().findVarHandle(AugmentableCodecDataObject.class,
+                "cachedAugmentations", ImmutableMap.class);
+        } catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
 
-    public AugmentableCodecDataObject(final DataObjectCodecContext<T, ?> context,
-            final NormalizedNodeContainer<?, ?, ?> data) {
-        super(data);
-        this.context = requireNonNull(context, "Context must not be null");
+    // Used via VarHandle
+    @SuppressWarnings("unused")
+    @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749")
+    private volatile ImmutableMap<Class<? extends Augmentation<T>>, Augmentation<T>> cachedAugmentations;
+
+    protected AugmentableCodecDataObject(final AbstractDataObjectCodecContext<T, ?> context,
+            final DataContainerNode data) {
+        super(context, data);
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public final <A extends Augmentation<T>> @Nullable A augmentation(final Class<A> augmentationType) {
         requireNonNull(augmentationType, "Supplied augmentation must not be null.");
 
-        final ImmutableClassToInstanceMap<Augmentation<T>> aug = cachedAugmentations;
+        final var aug = acquireAugmentations();
         if (aug != null) {
-            return aug.getInstance(augmentationType);
+            return (A) aug.get(augmentationType);
         }
 
-        @SuppressWarnings({"unchecked","rawtypes"})
-        final Optional<DataContainerCodecContext<?, ?>> optAugCtx = context.possibleStreamChild(
-            (Class) augmentationType);
-        if (optAugCtx.isPresent()) {
-            final DataContainerCodecContext<?, ?> augCtx = optAugCtx.get();
-            // Due to binding specification not representing grouping instantiations we can end up having the same
-            // augmentation applied to a grouping multiple times. While these augmentations have the same shape, they
-            // are still represented by distinct binding classes and therefore we need to make sure the result matches
-            // the augmentation the user is requesting -- otherwise a strict receiver would end up with a cryptic
-            // ClassCastException.
-            if (augmentationType.isAssignableFrom(augCtx.getBindingClass())) {
-                final Optional<NormalizedNode<?, ?>> augData = codecData().getChild(augCtx.getDomPathArgument());
-                if (augData.isPresent()) {
-                    return (A) augCtx.deserialize(augData.get());
-                }
+        @SuppressWarnings("rawtypes")
+        final var augCtx = (AugmentationCodecContext<A>) codecContext().streamChild((Class) augmentationType);
+        // Due to binding specification not representing grouping instantiations we can end up having the same
+        // augmentation applied to a grouping multiple times. While these augmentations have the same shape, they are
+        // still represented by distinct binding classes and therefore we need to make sure the result matches
+        // the augmentation the user is requesting -- otherwise a strict receiver would end up with a cryptic
+        // ClassCastException.
+        if (augCtx != null && augmentationType.isAssignableFrom(augCtx.getBindingClass())) {
+            final var augObj = augCtx.filterFrom(codecData());
+            if (augObj != null) {
+                return augObj;
             }
         }
         return null;
     }
 
     @Override
-    public final Map<Class<? extends Augmentation<T>>, Augmentation<T>> augmentations() {
-        ImmutableClassToInstanceMap<Augmentation<T>> local = cachedAugmentations;
-        if (local != null) {
-            return local;
-        }
-
-        local = ImmutableClassToInstanceMap.copyOf(context.getAllAugmentationsFrom(codecData()));
-        return CACHED_AUGMENTATIONS_UPDATER.compareAndSet(this, null, local) ? local : cachedAugmentations;
+    public final ImmutableMap<Class<? extends Augmentation<T>>, Augmentation<T>> augmentations() {
+        final var local = acquireAugmentations();
+        return local != null ? local : loadAugmentations();
     }
 
-    @Override
-    final int codecAugmentedHashCode() {
-        return 31 * super.codecAugmentedHashCode() + augmentations().hashCode();
+    private ImmutableMap<Class<? extends Augmentation<T>>, Augmentation<T>> acquireAugmentations() {
+        return (ImmutableMap<Class<? extends Augmentation<T>>, Augmentation<T>>) CACHED_AUGMENTATIONS.getAcquire(this);
     }
 
-    @Override
-    final boolean codecAugmentedEquals(final T other) {
-        return super.codecAugmentedEquals(other) && augmentations().equals(getAllAugmentations(other));
-    }
-
-    @Override
-    final ToStringHelper codecAugmentedFillToString(final ToStringHelper helper) {
-        return super.codecAugmentedFillToString(helper).add("augmentations", augmentations());
-    }
-
-    private static Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAllAugmentations(
-            final Augmentable<?> dataObject) {
-        if (dataObject instanceof AugmentationReader) {
-            return ((AugmentationReader) dataObject).getAugmentations(dataObject);
-        }
-        return BindingReflections.getAugmentations(dataObject);
+    @SuppressWarnings("unchecked")
+    private @NonNull ImmutableMap<Class<? extends Augmentation<T>>, Augmentation<T>> loadAugmentations() {
+        @SuppressWarnings("rawtypes")
+        final Map extracted = codecContext().getAllAugmentationsFrom(codecData());
+        final var ret = ImmutableMap.<Class<? extends Augmentation<T>>, Augmentation<T>>copyOf(extracted);
+        final Object witness = CACHED_AUGMENTATIONS.compareAndExchangeRelease(this, null, ret);
+        return witness == null ? ret : (ImmutableMap<Class<? extends Augmentation<T>>, Augmentation<T>>) witness;
     }
 }