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%2FLazyDataObjectModification.java;h=fc2c9366ec3705d30c238017154a378b5f88be4d;hb=e5ad7bce7fe6ffc268636656085a147906cefd7f;hp=e7046162c4ba1724a701e96b1a79ab82349c3a9e;hpb=eba291adf975802b00780ef36d904b4a142e18a6;p=mdsal.git diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/LazyDataObjectModification.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/LazyDataObjectModification.java index e7046162c4..fc2c9366ec 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/LazyDataObjectModification.java +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/LazyDataObjectModification.java @@ -7,21 +7,22 @@ */ package org.opendaylight.mdsal.binding.dom.adapter; -import org.opendaylight.mdsal.binding.api.DataObjectModification; - -import com.google.common.base.Optional; +import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; -import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeNode; +import java.util.Optional; +import org.opendaylight.mdsal.binding.api.DataObjectModification; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeNode; import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.ChildOf; 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; +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.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -32,6 +33,7 @@ import org.slf4j.LoggerFactory; /** * Lazily translated {@link DataObjectModification} based on {@link DataTreeCandidateNode}. * + *

* {@link LazyDataObjectModification} represents Data tree change event, * but whole tree is not translated or resolved eagerly, but only child nodes * which are directly accessed by user of data object modification. @@ -40,12 +42,14 @@ import org.slf4j.LoggerFactory; */ final class LazyDataObjectModification implements DataObjectModification { - private final static Logger LOG = LoggerFactory.getLogger(LazyDataObjectModification.class); + private static final Logger LOG = LoggerFactory.getLogger(LazyDataObjectModification.class); private final BindingCodecTreeNode codec; private final DataTreeCandidateNode domData; private final PathArgument identifier; - private Collection> childNodesCache; + + private volatile Collection> childNodesCache; + private volatile ModificationType modificationType; private LazyDataObjectModification(final BindingCodecTreeNode codec, final DataTreeCandidateNode domData) { this.codec = Preconditions.checkNotNull(codec); @@ -58,8 +62,8 @@ final class LazyDataObjectModification implements DataObje return new LazyDataObjectModification<>(codec,domData); } - private static Collection> from(final BindingCodecTreeNode parentCodec, - final Collection domChildNodes) { + private static Collection> from(final BindingCodecTreeNode + parentCodec, final Collection domChildNodes) { final List> result = new ArrayList<>(domChildNodes.size()); populateList(result, parentCodec, domChildNodes); return result; @@ -104,8 +108,8 @@ final class LazyDataObjectModification implements DataObje case UNKNOWN: case VISIBLE_CONTAINER: result.add(create(childCodec, domChildNode)); - default: break; + default: } } @@ -137,29 +141,81 @@ final class LazyDataObjectModification implements DataObje } @Override - public DataObjectModification.ModificationType getModificationType() { - switch(domData.getModificationType()) { + public ModificationType getModificationType() { + ModificationType localType = modificationType; + if (localType != null) { + return localType; + } + + switch (domData.getModificationType()) { case APPEARED: case WRITE: - return DataObjectModification.ModificationType.WRITE; - case SUBTREE_MODIFIED: - return DataObjectModification.ModificationType.SUBTREE_MODIFIED; + localType = ModificationType.WRITE; + break; case DISAPPEARED: case DELETE: - return DataObjectModification.ModificationType.DELETE; - + localType = ModificationType.DELETE; + break; + case SUBTREE_MODIFIED: + localType = resolveSubtreeModificationType(); + break; default: // TODO: Should we lie about modification type instead of exception? throw new IllegalStateException("Unsupported DOM Modification type " + domData.getModificationType()); } + + modificationType = localType; + return localType; + } + + private ModificationType resolveSubtreeModificationType() { + switch (codec.getChildAddressabilitySummary()) { + case ADDRESSABLE: + // All children are addressable, it is safe to report SUBTREE_MODIFIED + return ModificationType.SUBTREE_MODIFIED; + case UNADDRESSABLE: + // All children are non-addressable, report WRITE + return ModificationType.WRITE; + case MIXED: + // This case is not completely trivial, as we may have NOT_ADDRESSABLE nodes underneath us. If that + // is the case, we need to turn this modification into a WRITE operation, so that the user is able + // to observe those nodes being introduced. This is not efficient, but unfortunately unavoidable, + // as we cannot accurately represent such changes. + for (DataTreeCandidateNode child : domData.getChildNodes()) { + if (BindingStructuralType.recursiveFrom(child) == BindingStructuralType.NOT_ADDRESSABLE) { + // We have a non-addressable child, turn this modification into a write + return ModificationType.WRITE; + } + } + + // No unaddressable children found, proceed in addressed mode + return ModificationType.SUBTREE_MODIFIED; + default: + throw new IllegalStateException("Unsupported child addressability summary " + + codec.getChildAddressabilitySummary()); + } } @Override public Collection> getModifiedChildren() { - if (childNodesCache == null) { - childNodesCache = from(codec, domData.getChildNodes()); + Collection> local = childNodesCache; + if (local == null) { + childNodesCache = local = from(codec, domData.getChildNodes()); } - return childNodesCache; + return local; + } + + @SuppressWarnings("unchecked") + @Override + public > Collection> + getModifiedChildren(final Class childType) { + List> children = new ArrayList<>(); + for (DataObjectModification potential : getModifiedChildren()) { + if (childType.isAssignableFrom(potential.getDataType())) { + children.add((DataObjectModification) potential); + } + } + return children; } @Override @@ -179,22 +235,27 @@ final class LazyDataObjectModification implements DataObje @Override @SuppressWarnings("unchecked") - public & ChildOf, K extends Identifier> DataObjectModification getModifiedChildListItem( - final Class listItem, final K listKey) { - return (DataObjectModification) getModifiedChild(new InstanceIdentifier.IdentifiableItem<>(listItem, listKey)); + public & ChildOf, K extends Identifier> DataObjectModification + getModifiedChildListItem(final Class listItem, final K listKey) { + return (DataObjectModification) getModifiedChild(IdentifiableItem.of(listItem, listKey)); } @Override @SuppressWarnings("unchecked") public > DataObjectModification getModifiedChildContainer(final Class arg) { - return (DataObjectModification) getModifiedChild(new InstanceIdentifier.Item<>(arg)); + return (DataObjectModification) getModifiedChild(Item.of(arg)); } @Override @SuppressWarnings("unchecked") public & DataObject> DataObjectModification getModifiedAugmentation( final Class augmentation) { - return (DataObjectModification) getModifiedChild(new InstanceIdentifier.Item<>(augmentation)); + return (DataObjectModification) getModifiedChild(Item.of(augmentation)); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("identifier", identifier).add("domData", domData).toString(); } private T deserialize(final Optional> dataAfter) {