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=a165242b30f08d29902240d868b24ca84464fde9;hb=cd184f0a4226f20838c72ac1fdaf6fa19585df3b;hpb=78527e81f8cc82140af5cb2649863a597f380291 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 a165242b30..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; @@ -37,14 +42,16 @@ import org.slf4j.LoggerFactory; * * @param Type of Binding Data Object */ -class LazyDataObjectModification implements DataObjectModification { +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 @@ class LazyDataObjectModification implements DataObjectModi 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); } - 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); @@ -79,7 +86,7 @@ class LazyDataObjectModification implements DataObjectModi parentCodec.yangPathArgumentChild(domChildNode.getIdentifier()); populateList(result,type, childCodec, domChildNode); } catch (final IllegalArgumentException e) { - if(type == BindingStructuralType.UNKNOWN) { + if (type == BindingStructuralType.UNKNOWN) { LOG.debug("Unable to deserialize unknown DOM node {}",domChildNode,e); } else { LOG.debug("Binding representation for DOM node {} was not found",domChildNode,e); @@ -89,8 +96,7 @@ class LazyDataObjectModification implements DataObjectModi } } - - 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) { @@ -104,18 +110,24 @@ class LazyDataObjectModification implements DataObjectModi 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)); } } + @Override + public T getDataBefore() { + return deserialize(domData.getDataBefore()); + } + @Override public T getDataAfter() { return deserialize(domData.getDataAfter()); @@ -132,27 +144,85 @@ class LazyDataObjectModification implements DataObjectModi } @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 @@ -172,28 +242,45 @@ class LazyDataObjectModification implements DataObjectModi @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)); + 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 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 + "}"; } }