X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-binding-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fbinding%2Fimpl%2FLazyDataObjectModification.java;h=c3aff15e7a600f4fe83743e1ee77688273dc46db;hp=83d48f77a0889ca9019d88e00cf7f8bb08ba44c6;hb=cd184f0a4226f20838c72ac1fdaf6fa19585df3b;hpb=dbff1740fe3e5a1f007c183ecc27d25915866945 diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataObjectModification.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataObjectModification.java index 83d48f77a0..c3aff15e7a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataObjectModification.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/LazyDataObjectModification.java @@ -7,20 +7,25 @@ */ package org.opendaylight.controller.md.sal.binding.impl; -import com.google.common.base.Optional; import com.google.common.base.Preconditions; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; -import org.opendaylight.yangtools.binding.data.codec.api.BindingCodecTreeNode; +import org.opendaylight.mdsal.binding.dom.adapter.BindingStructuralType; +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.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; +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; @@ -39,12 +44,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); @@ -52,19 +59,19 @@ final class LazyDataObjectModification implements DataObje this.identifier = codec.deserializePathArgument(domData.getIdentifier()); } - static DataObjectModification create(final BindingCodecTreeNode codec, + static LazyDataObjectModification create(final BindingCodecTreeNode codec, final DataTreeCandidateNode domData) { return new LazyDataObjectModification<>(codec,domData); } - private static Collection> from(final BindingCodecTreeNode parentCodec, - final Collection domChildNodes) { - final ArrayList> result = new ArrayList<>(domChildNodes.size()); + private static Collection> from( + final BindingCodecTreeNode parentCodec, final Collection domChildNodes) { + final List> result = new ArrayList<>(domChildNodes.size()); populateList(result, parentCodec, domChildNodes); return result; } - private static void populateList(final List> result, + private static void populateList(final List> result, final BindingCodecTreeNode parentCodec, final Collection domChildNodes) { for (final DataTreeCandidateNode domChildNode : domChildNodes) { final BindingStructuralType type = BindingStructuralType.from(domChildNode); @@ -89,7 +96,7 @@ final class LazyDataObjectModification implements DataObje } } - private static void populateList(final List> result, + private static void populateList(final List> result, final BindingStructuralType type, final BindingCodecTreeNode childCodec, final DataTreeCandidateNode domChildNode) { switch (type) { @@ -103,12 +110,13 @@ final class LazyDataObjectModification implements DataObje case UNKNOWN: case VISIBLE_CONTAINER: result.add(create(childCodec, domChildNode)); + break; default: break; } } - private static void populateListWithSingleCodec(final List> result, + private static void populateListWithSingleCodec(final List> result, final BindingCodecTreeNode codec, final Collection childNodes) { for (final DataTreeCandidateNode child : childNodes) { result.add(create(codec, child)); @@ -136,27 +144,85 @@ 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()); + public Collection> getModifiedChildren() { + Collection> local = childNodesCache; + if (local == null) { + childNodesCache = local = from(codec, domData.getChildNodes()); } - return childNodesCache; + return local; + } + + @Override + public & DataObject, C extends ChildOf> + Collection> getModifiedChildren(final Class caseType, + final Class childType) { + return streamModifiedChildren(childType) + .filter(child -> caseType.equals(child.identifier.getCaseType().orElse(null))) + .collect(Collectors.toList()); + } + + @SuppressWarnings("unchecked") + private Stream> streamModifiedChildren( + final Class childType) { + return getModifiedChildren().stream() + .filter(child -> childType.isAssignableFrom(child.getDataType())) + .map(child -> (LazyDataObjectModification) child); } @Override @@ -176,28 +242,45 @@ 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 & DataObject, C extends Identifiable & ChildOf, + K extends Identifier> DataObjectModification getModifiedChildListItem(final Class caseType, + final Class listItem, final K listKey) { + return (DataObjectModification) getModifiedChild(IdentifiableItem.of(caseType, listItem, listKey)); } @Override @SuppressWarnings("unchecked") - public > DataObjectModification getModifiedChildContainer(final Class arg) { - return (DataObjectModification) getModifiedChild(new InstanceIdentifier.Item<>(arg)); + public > DataObjectModification getModifiedChildContainer(final Class child) { + return (DataObjectModification) getModifiedChild(Item.of(child)); + } + + @Override + @SuppressWarnings("unchecked") + public & DataObject, C extends ChildOf> DataObjectModification + getModifiedChildContainer(final Class caseType, final Class child) { + return (DataObjectModification) getModifiedChild(Item.of(caseType, child)); } @Override @SuppressWarnings("unchecked") public & DataObject> DataObjectModification getModifiedAugmentation( final Class augmentation) { - return (DataObjectModification) getModifiedChild(new InstanceIdentifier.Item<>(augmentation)); + return (DataObjectModification) getModifiedChild(Item.of(augmentation)); } private T deserialize(final Optional> dataAfter) { - if (dataAfter.isPresent()) { - return codec.deserialize(dataAfter.get()); - } - return null; + return dataAfter.map(codec::deserialize).orElse(null); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{identifier = " + identifier + ", domData = " + domData + "}"; } }