@Override
public Collection<DataTreeCandidateNode> getChildNodes() {
switch (mod.getModificationType()) {
+ case APPEARED:
+ case DISAPPEARED:
case SUBTREE_MODIFIED:
return Collections2.transform(mod.getChildren(), new Function<ModifiedNode, DataTreeCandidateNode>() {
@Override
@Override
public final DataTreeCandidateNode getModifiedChild(final PathArgument identifier) {
switch (mod.getModificationType()) {
+ case APPEARED:
+ case DISAPPEARED:
case SUBTREE_MODIFIED:
final Optional<ModifiedNode> childMod = mod.getChild(identifier);
if (childMod.isPresent()) {
return getMod().getIdentifier();
}
}
-}
\ No newline at end of file
+}
final ImmutableMap.Builder<YangInstanceIdentifier.PathArgument, ModificationApplyOperation> child = ImmutableMap.builder();
for (final ChoiceCaseNode caze : schemaNode.getCases()) {
- if(SchemaAwareApplyOperation.belongsToTree(treeType,caze)) {
+ if (SchemaAwareApplyOperation.belongsToTree(treeType,caze)) {
for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
- if(SchemaAwareApplyOperation.belongsToTree(treeType,cazeChild)) {
- final SchemaAwareApplyOperation childNode = SchemaAwareApplyOperation.from(cazeChild,treeType);
+ if (SchemaAwareApplyOperation.belongsToTree(treeType,cazeChild)) {
+ final ModificationApplyOperation childNode = SchemaAwareApplyOperation.from(cazeChild, treeType);
child.put(NodeIdentifier.create(cazeChild.getQName()), childNode);
}
}
checkArgument(original instanceof ChoiceNode);
return ImmutableChoiceNodeBuilder.create((ChoiceNode) original);
}
-}
\ No newline at end of file
+}
return new InMemoryDataTreeSnapshot(schemaContext, root, holder.newSnapshot());
}
- DataTreeState withSchemaContext(final SchemaContext newSchemaContext, final SchemaAwareApplyOperation operation) {
+ DataTreeState withSchemaContext(final SchemaContext newSchemaContext, final ModificationApplyOperation operation) {
holder.setCurrent(operation);
return new DataTreeState(root, holder, newSchemaContext);
}
package org.opendaylight.yangtools.yang.data.impl.schema.tree;
import com.google.common.base.MoreObjects;
-import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.StoreTreeNodes;
import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
LOG.debug("Following schema contexts will be attempted {}", newSchemaContext);
- final ModificationApplyOperation op = SchemaAwareApplyOperation.from(newSchemaContext, treeType);
- final Optional<ModificationApplyOperation> maybeRootNode = StoreTreeNodes.findNode(op, rootPath);
- if (!maybeRootNode.isPresent()) {
+ final DataSchemaContextTree contextTree = DataSchemaContextTree.from(newSchemaContext);
+ final DataSchemaContextNode<?> rootContextNode = contextTree.getChild(rootPath);
+ if (rootContextNode == null) {
LOG.debug("Could not find root {} in new schema context, not upgrading", rootPath);
return;
}
- final ModificationApplyOperation rootNode = maybeRootNode.get();
- if (!(rootNode instanceof AbstractNodeContainerModificationStrategy)) {
- LOG.warn("Root {} resolves to non-container type {}, not upgrading", rootPath, rootNode);
+ final DataSchemaNode rootSchemaNode = rootContextNode.getDataSchemaNode();
+ if (!(rootSchemaNode instanceof DataNodeContainer)) {
+ LOG.warn("Root {} resolves to non-container type {}, not upgrading", rootPath, rootSchemaNode);
return;
}
+ final ModificationApplyOperation rootNode;
+ if (rootSchemaNode instanceof ContainerSchemaNode) {
+ rootNode = new PresenceContainerModificationStrategy((ContainerSchemaNode) rootSchemaNode, treeType);
+ } else {
+ rootNode = SchemaAwareApplyOperation.from(rootSchemaNode, treeType);
+ }
+
DataTreeState currentState, newState;
do {
currentState = state;
- newState = currentState.withSchemaContext(newSchemaContext, (SchemaAwareApplyOperation) rootNode);
+ newState = currentState.withSchemaContext(newSchemaContext, rootNode);
} while (!STATE_UPDATER.compareAndSet(this, currentState, newState));
}
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-final class ContainerModificationStrategy extends AbstractDataNodeContainerModificationStrategy<ContainerSchemaNode> {
- ContainerModificationStrategy(final ContainerSchemaNode schemaNode, final TreeType treeType) {
+final class PresenceContainerModificationStrategy extends
+ AbstractDataNodeContainerModificationStrategy<ContainerSchemaNode> {
+ PresenceContainerModificationStrategy(final ContainerSchemaNode schemaNode, final TreeType treeType) {
super(schemaNode, ContainerNode.class, treeType);
}
checkArgument(original instanceof ContainerNode);
return ImmutableContainerNodeBuilder.create((ContainerNode) original);
}
-}
+}
\ No newline at end of file
abstract class SchemaAwareApplyOperation extends ModificationApplyOperation {
private static final Logger LOG = LoggerFactory.getLogger(SchemaAwareApplyOperation.class);
- static SchemaAwareApplyOperation from(final ContainerSchemaNode schemaNode, final TreeType treeType) {
- return new ContainerModificationStrategy(schemaNode, treeType);
- }
-
- public static SchemaAwareApplyOperation from(final DataSchemaNode schemaNode, final TreeType treeType) {
- if(treeType == TreeType.CONFIGURATION) {
+ public static ModificationApplyOperation from(final DataSchemaNode schemaNode, final TreeType treeType) {
+ if (treeType == TreeType.CONFIGURATION) {
Preconditions.checkArgument(schemaNode.isConfiguration(), "Supplied %s does not belongs to configuration tree.", schemaNode.getPath());
}
if (schemaNode instanceof ContainerSchemaNode) {
- return new ContainerModificationStrategy((ContainerSchemaNode) schemaNode, treeType);
+ final ContainerSchemaNode containerSchema = (ContainerSchemaNode) schemaNode;
+ if (containerSchema.isPresenceContainer()) {
+ return new PresenceContainerModificationStrategy(containerSchema, treeType);
+ } else {
+ return new StructuralContainerModificationStrategy(containerSchema, treeType);
+ }
} else if (schemaNode instanceof ListSchemaNode) {
return fromListSchemaNode((ListSchemaNode) schemaNode, treeType);
} else if (schemaNode instanceof ChoiceSchemaNode) {
--- /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.yangtools.yang.data.impl.schema.tree;
+
+import com.google.common.base.Optional;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.TreeNodeFactory;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.spi.Version;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+
+/**
+ * Structural containers are special in that they appear when implied by child
+ * nodes and disappear whenever they are empty. We could implement this as a
+ * subclass of {@link SchemaAwareApplyOperation}, but the automatic semantic
+ * is quite different from all the other strategies. We create a
+ * {@link PresenceContainerModificationStrategy} to tap into that logic, but
+ * wrap it so we only call out into it
+ */
+final class StructuralContainerModificationStrategy extends ModificationApplyOperation {
+ /**
+ * Fake TreeNode version used in {@link #checkApplicable(YangInstanceIdentifier, NodeModification, Optional)}.
+ * It is okay to use a global constant, as the delegate will ignore it anyway. For
+ * {@link #apply(ModifiedNode, Optional, Version)} we will use the appropriate version as provided to us.
+ */
+ private static final Version FAKE_VERSION = Version.initial();
+ private final PresenceContainerModificationStrategy delegate;
+
+ StructuralContainerModificationStrategy(final ContainerSchemaNode schemaNode, final TreeType treeType) {
+ this.delegate = new PresenceContainerModificationStrategy(schemaNode, treeType);
+ }
+
+ private Optional<TreeNode> fakeMeta(final Version version) {
+ final ContainerNode container = ImmutableNodes.containerNode(delegate.getSchema().getQName());
+ return Optional.of(TreeNodeFactory.createTreeNode(container, version));
+ }
+
+ @Override
+ Optional<TreeNode> apply(final ModifiedNode modification, final Optional<TreeNode> storeMeta, final Version version) {
+ final Optional<TreeNode> ret;
+ if (modification.getOperation() == LogicalOperation.TOUCH && !storeMeta.isPresent()) {
+ // Container is not present, let's take care of the 'magically appear' part of our job
+ ret = delegate.apply(modification, fakeMeta(version), version);
+
+ // Fake container got removed: that is a no-op
+ if (!ret.isPresent()) {
+ modification.resolveModificationType(ModificationType.UNMODIFIED);
+ return ret;
+ }
+
+ // If the delegate indicated SUBTREE_MODIFIED, account for the fake and report APPEARED
+ if (modification.getModificationType() == ModificationType.SUBTREE_MODIFIED) {
+ modification.resolveModificationType(ModificationType.APPEARED);
+ }
+ } else {
+ // Container is present, run normal apply operation
+ ret = delegate.apply(modification, storeMeta, version);
+
+ // Container was explicitly deleted, no magic required
+ if (!ret.isPresent()) {
+ return ret;
+ }
+ }
+
+ /*
+ * At this point ret is guaranteed to be present. We need to take care of the 'magically disappear' part of
+ * our job. Check if there are any child nodes left. If there are none, remove this container and turn the
+ * modification into a DISAPPEARED.
+ */
+ if (((NormalizedNodeContainer<?, ?, ?>) ret.get().getData()).getValue().isEmpty()) {
+ modification.resolveModificationType(ModificationType.DISAPPEARED);
+ return Optional.absent();
+ }
+
+ return ret;
+ }
+
+ @Override
+ void checkApplicable(final YangInstanceIdentifier path, final NodeModification modification, final Optional<TreeNode> current) throws DataValidationFailedException {
+ if (modification.getOperation() == LogicalOperation.TOUCH && !current.isPresent()) {
+ // Structural containers are created as needed, so we pretend this container is here
+ delegate.checkApplicable(path, modification, fakeMeta(FAKE_VERSION));
+ } else {
+ delegate.checkApplicable(path, modification, current);
+ }
+ }
+
+ @Override
+ void verifyStructure(final NormalizedNode<?, ?> modification, final boolean verifyChildren) throws IllegalArgumentException {
+ delegate.verifyStructure(modification, verifyChildren);
+ }
+
+ @Override
+ ChildTrackingPolicy getChildPolicy() {
+ return delegate.getChildPolicy();
+ }
+
+ @Override
+ public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
+ return delegate.getChild(child);
+ }
+}
}
container master-container {
+ presence true;
list min-max-list {
min-elements 2;
max-elements 3;
}
container test {
+ presence true;
choice choice1 {
case case1 {
leaf case1-leaf1 {
}
}
list inner-list {
- config false;
+ config false;
key name;
leaf name {
type string;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import java.util.Iterator;
+import javax.annotation.Nonnull;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
public final class DataSchemaContextTree {
-
private static final LoadingCache<SchemaContext, DataSchemaContextTree> TREES = CacheBuilder.newBuilder()
.weakKeys()
.build(new CacheLoader<SchemaContext, DataSchemaContextTree>() {
@Override
- public DataSchemaContextTree load(SchemaContext key) throws Exception {
+ public DataSchemaContextTree load(final SchemaContext key) throws Exception {
return new DataSchemaContextTree(key);
}
root = DataSchemaContextNode.from(ctx);
}
-
- public static DataSchemaContextTree from(SchemaContext ctx) {
+ @Nonnull public static DataSchemaContextTree from(@Nonnull final SchemaContext ctx) {
return TREES.getUnchecked(ctx);
}
public DataSchemaContextNode<?> getRoot() {
return root;
}
-
}