X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-dom-adapter%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fdom%2Fadapter%2FAbstractDataObjectModification.java;h=57ab7c906ece3620e00d1c69d0fc09224df80d92;hb=9f23891d96e635e1cd30c699f9b72b9336fc9d06;hp=e0672ae9db0f47d1e8445152fc4ab3b382fedc5b;hpb=5901ab384ee5e8c77c19a0e6fde35b7804973dbd;p=mdsal.git diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractDataObjectModification.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractDataObjectModification.java index e0672ae9db..57ab7c906e 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractDataObjectModification.java +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractDataObjectModification.java @@ -7,6 +7,7 @@ */ package org.opendaylight.mdsal.binding.dom.adapter; +import static com.google.common.base.Verify.verifyNotNull; import static java.util.Objects.requireNonNull; import static org.opendaylight.yangtools.yang.data.tree.api.ModificationType.UNMODIFIED; @@ -15,10 +16,12 @@ import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.base.VerifyException; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNull; @@ -31,11 +34,11 @@ import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.ChildOf; import org.opendaylight.yangtools.yang.binding.ChoiceIn; import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.Identifiable; -import org.opendaylight.yangtools.yang.binding.Identifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.binding.Key; +import org.opendaylight.yangtools.yang.binding.KeyAware; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateNode; @@ -58,15 +61,43 @@ abstract sealed class AbstractDataObjectModification permits LazyAugmentationModification, LazyDataObjectModification { private static final Logger LOG = LoggerFactory.getLogger(AbstractDataObjectModification.class); + private static final @NonNull Object NULL_DATA_OBJECT = new Object(); + private static final VarHandle MODIFICATION_TYPE; + private static final VarHandle MODIFIED_CHILDREN; + private static final VarHandle DATA_BEFORE; + private static final VarHandle DATA_AFTER; + + static { + final var lookup = MethodHandles.lookup(); + + try { + MODIFICATION_TYPE = lookup.findVarHandle(AbstractDataObjectModification.class, "modificationType", + ModificationType.class); + MODIFIED_CHILDREN = lookup.findVarHandle(AbstractDataObjectModification.class, "modifiedChildren", + ImmutableList.class); + DATA_BEFORE = lookup.findVarHandle(AbstractDataObjectModification.class, "dataBefore", Object.class); + DATA_AFTER = lookup.findVarHandle(AbstractDataObjectModification.class, "dataAfter", Object.class); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ExceptionInInitializerError(e); + } + } final @NonNull DataTreeCandidateNode domData; final @NonNull PathArgument identifier; final @NonNull N codec; - private volatile ImmutableList> childNodesCache; + @SuppressWarnings("unused") + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749") + private volatile ImmutableList> modifiedChildren; + @SuppressWarnings("unused") + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749") private volatile ModificationType modificationType; - private volatile @Nullable T dataBefore; - private volatile @Nullable T dataAfter; + @SuppressWarnings("unused") + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749") + private volatile Object dataBefore; + @SuppressWarnings("unused") + @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749") + private volatile Object dataAfter; AbstractDataObjectModification(final DataTreeCandidateNode domData, final N codec, final PathArgument identifier) { this.domData = requireNonNull(domData); @@ -97,13 +128,13 @@ abstract sealed class AbstractDataObjectModification ModificationType.WRITE; case DISAPPEARED, DELETE -> ModificationType.DELETE; case SUBTREE_MODIFIED -> resolveSubtreeModificationType(); @@ -111,29 +142,46 @@ abstract sealed class AbstractDataObjectModification @NonNull Object mask(final @Nullable T obj) { + return obj != null ? obj : NULL_DATA_OBJECT; + } + + @SuppressWarnings("unchecked") + private @Nullable T unmask(final @NonNull Object obj) { + return obj == NULL_DATA_OBJECT ? null : (T) verifyNotNull(obj); } - private @Nullable T deserialize(final Optional normalized) { - return normalized.isEmpty() ? null : deserialize(normalized.orElseThrow()); + private @Nullable T deserializeNullable(final @Nullable NormalizedNode normalized) { + return normalized == null ? null : deserialize(normalized); } abstract @Nullable T deserialize(@NonNull NormalizedNode normalized); @@ -148,10 +196,10 @@ abstract sealed class AbstractDataObjectModification> getModifiedChildren() { - var local = childNodesCache; - if (local == null) { - childNodesCache = local = createModifiedChilden(codec, domData, domChildNodes()); - } - return local; + final var local = (ImmutableList>) MODIFIED_CHILDREN.getAcquire(this); + return local != null ? local : loadModifiedChilden(); } @Override @@ -182,6 +227,16 @@ abstract sealed class AbstractDataObjectModification> loadModifiedChilden() { + final var builder = ImmutableList.>builder(); + populateList(builder, codec, domData, domChildNodes()); + final var computed = builder.build(); + // Non-trivial return: use CAS to ensure we reuse concurrent loads + final var witness = MODIFIED_CHILDREN.compareAndExchangeRelease(this, null, computed); + return witness == null ? computed : (ImmutableList>) witness; + } + @SuppressWarnings("unchecked") private Stream> streamModifiedChildren( final Class childType) { @@ -192,15 +247,15 @@ abstract sealed class AbstractDataObjectModification & ChildOf, K extends Identifier> DataObjectModification + public final & ChildOf, K extends Key> DataObjectModification getModifiedChildListItem(final Class listItem, final K listKey) { return (DataObjectModification) getModifiedChild(IdentifiableItem.of(listItem, listKey)); } @Override @SuppressWarnings("unchecked") - public final & DataObject, C extends Identifiable & ChildOf, - K extends Identifier> DataObjectModification getModifiedChildListItem(final Class caseType, + public final & DataObject, C extends KeyAware & ChildOf, + K extends Key> DataObjectModification getModifiedChildListItem(final Class caseType, final Class listItem, final K listKey) { return (DataObjectModification) getModifiedChild(IdentifiableItem.of(caseType, listItem, listKey)); } @@ -252,7 +307,7 @@ abstract sealed class AbstractDataObjectModification> createModifiedChilden( - final CommonDataObjectCodecTreeNode parentCodec, final DataTreeCandidateNode parent, - final Collection children) { - final var result = ImmutableList.>builder(); - populateList(result, parentCodec, parent, children); - return result.build(); - } - private static void populateList(final ImmutableList.Builder> result, final CommonDataObjectCodecTreeNode parentCodec, final DataTreeCandidateNode parent, final Collection children) { final var augmentChildren = ArrayListMultimap., DataTreeCandidateNode>create(); - for (var domChildNode : parent.getChildNodes()) { - if (domChildNode.getModificationType() != UNMODIFIED) { + for (var domChildNode : parent.childNodes()) { + if (domChildNode.modificationType() != UNMODIFIED) { final var type = BindingStructuralType.from(domChildNode); if (type != BindingStructuralType.NOT_ADDRESSABLE) { /* @@ -288,7 +335,7 @@ abstract sealed class AbstractDataObjectModification childDataObjectCodec) { populateList(result, type, childDataObjectCodec, domChildNode); } else if (childCodec instanceof BindingAugmentationCodecTreeNode childAugmentationCodec) { @@ -323,10 +370,10 @@ abstract sealed class AbstractDataObjectModification> result, final BindingDataObjectCodecTreeNode codec, final Collection childNodes) { for (var child : childNodes) { - if (child.getModificationType() != UNMODIFIED) { + if (child.modificationType() != UNMODIFIED) { result.add(new LazyDataObjectModification<>(codec, child)); } }