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=94f24c047fc2d03f9a6ee6242ec6f3698bfcd2bf;hb=4fc89fcbfd72f38e02bff533cab5fa3e4794cfcc;hp=9346e9a617c80011d37403ddd53e06e075bd38b4;hpb=670cf079450a54bf695e962800ee92412b2a443f;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 9346e9a617..94f24c047f 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,29 +16,31 @@ 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; import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.mdsal.binding.api.DataObjectModification; import org.opendaylight.mdsal.binding.dom.codec.api.BindingAugmentationCodecTreeNode; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingChoiceCodecTreeNode; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataContainerCodecTreeNode; import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; import org.opendaylight.mdsal.binding.dom.codec.api.CommonDataObjectCodecTreeNode; 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.ExactDataObjectStep; +import org.opendaylight.yangtools.yang.binding.Key; +import org.opendaylight.yangtools.yang.binding.KeyAware; +import org.opendaylight.yangtools.yang.binding.KeyStep; +import org.opendaylight.yangtools.yang.binding.NodeStep; 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; @@ -60,7 +63,11 @@ 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(); @@ -68,24 +75,36 @@ abstract sealed class AbstractDataObjectModification step; 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) { + AbstractDataObjectModification(final DataTreeCandidateNode domData, final N codec, + final ExactDataObjectStep step) { this.domData = requireNonNull(domData); - this.identifier = requireNonNull(identifier); + this.step = requireNonNull(step); this.codec = requireNonNull(codec); } @@ -101,17 +120,12 @@ abstract sealed class AbstractDataObjectModification getDataType() { - return codec.getBindingClass(); - } - - @Override - public final PathArgument getIdentifier() { - return identifier; + public final ExactDataObjectStep step() { + return step; } @Override - public final ModificationType getModificationType() { + public final ModificationType modificationType() { final var local = (ModificationType) MODIFICATION_TYPE.getAcquire(this); return local != null ? local : loadModificationType(); } @@ -132,31 +146,46 @@ abstract sealed class AbstractDataObjectModification normalized) { - return normalized.isEmpty() ? null : deserialize(normalized.orElseThrow()); + private static @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 deserializeNullable(final @Nullable NormalizedNode normalized) { + return normalized == null ? null : deserialize(normalized); } abstract @Nullable T deserialize(@NonNull NormalizedNode normalized); @Override - public final DataObjectModification getModifiedChild(final PathArgument arg) { + public final DataObjectModification getModifiedChild(final ExactDataObjectStep arg) { final var domArgumentList = new ArrayList(); final var childCodec = codec.bindingPathArgumentChild(arg, domArgumentList); final var toEnter = domArgumentList.iterator(); @@ -165,10 +194,10 @@ abstract sealed class AbstractDataObjectModification> getModifiedChildren() { - var local = childNodesCache; - if (local == null) { - childNodesCache = local = createModifiedChilden(codec, domData, domChildNodes()); - } - return local; + public final ImmutableList> modifiedChildren() { + final var local = (ImmutableList>) MODIFIED_CHILDREN.getAcquire(this); + return local != null ? local : loadModifiedChilden(); } @Override @@ -195,52 +221,62 @@ abstract sealed class AbstractDataObjectModification & DataObject, C extends ChildOf> List> getModifiedChildren(final Class caseType, final Class childType) { return streamModifiedChildren(childType) - .filter(child -> caseType.equals(child.identifier.getCaseType().orElse(null))) + .filter(child -> caseType.equals(child.step.caseType())) .collect(Collectors.toList()); } + @SuppressWarnings("unchecked") + private @NonNull ImmutableList> 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) { - return getModifiedChildren().stream() - .filter(child -> childType.isAssignableFrom(child.getDataType())) + return modifiedChildren().stream() + .filter(child -> childType.isAssignableFrom(child.dataType())) .map(child -> (LazyDataObjectModification) child); } @Override @SuppressWarnings("unchecked") - public final & 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)); + return (DataObjectModification) getModifiedChild(new KeyStep<>(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)); + return (DataObjectModification) getModifiedChild(new KeyStep<>(listItem, caseType, listKey)); } @Override @SuppressWarnings("unchecked") public final > DataObjectModification getModifiedChildContainer( final Class child) { - return (DataObjectModification) getModifiedChild(Item.of(child)); + return (DataObjectModification) getModifiedChild(new NodeStep<>(child)); } @Override @SuppressWarnings("unchecked") public final & DataObject, C extends ChildOf> DataObjectModification getModifiedChildContainer(final Class caseType, final Class child) { - return (DataObjectModification) getModifiedChild(Item.of(caseType, child)); + return (DataObjectModification) getModifiedChild(new NodeStep<>(caseType, child)); } @Override @SuppressWarnings("unchecked") public final & DataObject> DataObjectModification getModifiedAugmentation( final Class augmentation) { - return (DataObjectModification) getModifiedChild(Item.of(augmentation)); + return (DataObjectModification) getModifiedChild(new NodeStep<>(augmentation)); } @Override @@ -249,7 +285,7 @@ abstract sealed class AbstractDataObjectModification domChildNodes(); @@ -282,22 +318,14 @@ 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 BindingDataContainerCodecTreeNode 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) { /* @@ -305,12 +333,14 @@ abstract sealed class AbstractDataObjectModification childDataObjectCodec) { populateList(result, type, childDataObjectCodec, domChildNode); } else if (childCodec instanceof BindingAugmentationCodecTreeNode childAugmentationCodec) { // Defer creation once we have collected all modified children augmentChildren.put(childAugmentationCodec, domChildNode); + } else if (childCodec instanceof BindingChoiceCodecTreeNode childChoiceCodec) { + populateList(result, childChoiceCodec, domChildNode, domChildNode.childNodes()); } else { throw new VerifyException("Unhandled codec %s for type %s".formatted(childCodec, type)); } @@ -340,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)); } }