+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.md.sal.binding.impl;
-
-import com.google.common.base.Optional;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
-import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
-
-/**
- *
- * Defines structural mapping of Normalized Node to Binding data
- * addressable by Instance Identifier.
- *
- * Not all binding data are addressable by instance identifier
- * and there are some differences.
- *
- * See {@link #NOT_ADDRESSABLE},{@link #INVISIBLE_CONTAINER},{@link #VISIBLE_CONTAINER}
- * for more details.
- *
- *
- */
-enum BindingStructuralType {
-
- /**
- * DOM Item is not addressable in Binding Instance Identifier,
- * data is not lost, but are available only via parent object.
- *
- * Such types of data are leaf-lists, leafs, list without keys
- * or anyxml.
- *
- */
- NOT_ADDRESSABLE,
- /**
- * Data container is addressable in NormalizedNode format,
- * but in Binding it is not represented in Instance Identifier.
- *
- * This are choice / case nodes.
- *
- * This data is still accessible using parent object and their
- * children are addressable.
- *
- */
- INVISIBLE_CONTAINER,
- /**
- * Data container is addressable in NormalizedNode format,
- * but in Binding it is not represented in Instance Identifier.
- *
- * This are list nodes.
- *
- * This data is still accessible using parent object and their
- * children are addressable.
- *
- */
- INVISIBLE_LIST,
- /**
- * Data container is addressable in Binding Instance Identifier format
- * and also YangInstanceIdentifier format.
- *
- */
- VISIBLE_CONTAINER,
- /**
- * Mapping algorithm was unable to detect type or was not updated after introduction
- * of new NormalizedNode type.
- */
- UNKNOWN;
-
- static BindingStructuralType from(final DataTreeCandidateNode domChildNode) {
- final Optional<NormalizedNode<?, ?>> dataBased = domChildNode.getDataAfter().or(domChildNode.getDataBefore());
- if(dataBased.isPresent()) {
- return from(dataBased.get());
- }
- return from(domChildNode.getIdentifier());
- }
-
- private static BindingStructuralType from(final PathArgument identifier) {
- if(identifier instanceof NodeIdentifierWithPredicates || identifier instanceof AugmentationIdentifier) {
- return VISIBLE_CONTAINER;
- }
- if(identifier instanceof NodeWithValue) {
- return NOT_ADDRESSABLE;
- }
- return UNKNOWN;
- }
-
- static BindingStructuralType from(final NormalizedNode<?, ?> data) {
- if(isNotAddressable(data)) {
- return NOT_ADDRESSABLE;
- }
- if(data instanceof MapNode) {
- return INVISIBLE_LIST;
- }
- if(data instanceof ChoiceNode) {
- return INVISIBLE_CONTAINER;
- }
- if(isVisibleContainer(data)) {
- return VISIBLE_CONTAINER;
- }
- return UNKNOWN;
- }
-
- private static boolean isVisibleContainer(final NormalizedNode<?, ?> data) {
- return data instanceof MapEntryNode || data instanceof ContainerNode || data instanceof AugmentationNode;
- }
-
- private static boolean isNotAddressable(final NormalizedNode<?, ?> d) {
- return d instanceof LeafNode
- || d instanceof AnyXmlNode
- || d instanceof LeafSetNode
- || d instanceof LeafSetEntryNode;
- }
-
-}
import java.util.Iterator;
import java.util.List;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+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;
private final BindingCodecTreeNode<T> codec;
private final DataTreeCandidateNode domData;
private final PathArgument identifier;
- private Collection<DataObjectModification<? extends DataObject>> childNodesCache;
+
+ private volatile Collection<DataObjectModification<? extends DataObject>> childNodesCache;
+ private volatile ModificationType modificationType;
private LazyDataObjectModification(final BindingCodecTreeNode<T> codec, final DataTreeCandidateNode domData) {
this.codec = Preconditions.checkNotNull(codec);
}
@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<DataObjectModification<? extends DataObject>> getModifiedChildren() {
- if (childNodesCache == null) {
- childNodesCache = from(codec, domData.getChildNodes());
+ Collection<DataObjectModification<? extends DataObject>> local = childNodesCache;
+ if (local == null) {
+ childNodesCache = local = from(codec, domData.getChildNodes());
}
- return childNodesCache;
+ return local;
}
@Override