2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.data.api.schema.tree.spi;
10 import java.util.HashMap;
13 import org.opendaylight.yangtools.util.MapAdaptor;
14 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
15 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
16 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
17 import org.opendaylight.yangtools.yang.data.api.schema.OrderedNodeContainer;
19 import com.google.common.base.Optional;
20 import com.google.common.base.Preconditions;
23 * A TreeNode capable of holding child nodes. The fact that any of the children
24 * changed is tracked by the subtree version.
26 final class ContainerNode extends AbstractTreeNode {
27 private final Map<PathArgument, TreeNode> children;
28 private final Version subtreeVersion;
30 protected ContainerNode(final NormalizedNode<?, ?> data, final Version version,
31 final Map<PathArgument, TreeNode> children, final Version subtreeVersion) {
33 this.children = Preconditions.checkNotNull(children);
34 this.subtreeVersion = Preconditions.checkNotNull(subtreeVersion);
38 public Version getSubtreeVersion() {
39 return subtreeVersion;
43 public Optional<TreeNode> getChild(final PathArgument key) {
44 Optional<TreeNode> explicitNode = Optional.fromNullable(children.get(key));
45 if (explicitNode.isPresent()) {
48 final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> castedData = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>>) getData();
49 Optional<NormalizedNode<?, ?>> value = castedData.getChild(key);
50 if (value.isPresent()) {
51 //FIXME: consider caching created Tree Nodes.
52 //We are safe to not to cache them, since written Tree Nodes are in read only snapshot.
53 return Optional.of(TreeNodeFactory.createTreeNode(value.get(), getVersion()));
55 return Optional.absent();
59 public MutableTreeNode mutable() {
60 return new Mutable(this);
63 private static final class Mutable implements MutableTreeNode {
64 private final Version version;
65 private Map<PathArgument, TreeNode> children;
66 private NormalizedNode<?, ?> data;
67 private Version subtreeVersion;
69 private Mutable(final ContainerNode parent) {
70 this.data = parent.getData();
71 this.children = MapAdaptor.getDefaultInstance().takeSnapshot(parent.children);
72 this.subtreeVersion = parent.getSubtreeVersion();
73 this.version = parent.getVersion();
74 materializeChildVersion();
78 * Traverse whole data tree and instantiate children for each data node. Set version of each MutableTreeNode
79 * accordingly to version in data node.
81 * Use this method if TreeNode is lazy initialized.
83 private void materializeChildVersion() {
84 Preconditions.checkState(data instanceof NormalizedNodeContainer);
85 NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> castedData = (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) data;
87 for(NormalizedNode<?, ?> childData : castedData.getValue()) {
88 PathArgument id = childData.getIdentifier();
90 if (!children.containsKey(id)) {
91 children.put(id, TreeNodeFactory.createTreeNode(childData, version));
97 public Optional<TreeNode> getChild(final PathArgument child) {
98 return Optional.fromNullable(children.get(child));
102 public void setSubtreeVersion(final Version subtreeVersion) {
103 this.subtreeVersion = Preconditions.checkNotNull(subtreeVersion);
107 public void addChild(final TreeNode child) {
108 children.put(child.getIdentifier(), child);
112 public void removeChild(final PathArgument id) {
117 public TreeNode seal() {
118 final TreeNode ret = new ContainerNode(data, version, MapAdaptor.getDefaultInstance().optimize(children), subtreeVersion);
120 // This forces a NPE if this class is accessed again. Better than corruption.
126 public void setData(final NormalizedNode<?, ?> data) {
127 this.data = Preconditions.checkNotNull(data);
132 * Method creates and returns Container root Node and whole subtree for each child node specified in children nodes.
134 * Reason why is method used recursively is that for each child in children nodes there is call to
135 * {@link TreeNodeFactory#createTreeNodeRecursively}. Each call to <code>createTreeNodeRecursively</code>
136 * calls either {@link #createNormalizedNodeRecursively} or {@link #createOrderedNodeRecursively}
137 * which depends on type of child node.
138 * <br> The root node that is returned holds reference to data node and whole subtree of children also containing references
141 * @param version version of indexed data
142 * @param data reference to data node
143 * @param children direct children of root node that is being created
144 * @return Root node with reference to data node and whole subtree of child nodes
146 private static ContainerNode createNodeRecursively(final Version version, final NormalizedNode<?, ?> data,
147 final Iterable<NormalizedNode<?, ?>> children) {
149 final Map<PathArgument, TreeNode> map = new HashMap<>();
150 for (NormalizedNode<?, ?> child : children) {
151 map.put(child.getIdentifier(), TreeNodeFactory.createTreeNodeRecursively(child, version));
154 return new ContainerNode(data, version, map, version);
158 * Method creates and returns Normalized Node Container as root and recursively creates whole subtree
159 * from all of the container child iterables stored in {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer#getValue()}
161 * The reason why is this method called recursively is that in background method calls {@link TreeNodeFactory#createTreeNodeRecursively}
162 * for each child stored in NormalizedNode and after each child is created the method calls again {@link #createNormalizedNodeRecursively} method
163 * until all of the children are resolved.
165 * @param version version of indexed data
166 * @param container Normalized Node Container
167 * @return Normalized Node Container as root and all whole subtree created from container iterables.
169 public static ContainerNode createNormalizedNodeRecursively(final Version version,
170 final NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> container) {
171 return createNodeRecursively(version, container, container.getValue());
175 * Method creates and returns Ordered Node Container as root and recursively creates whole subtree
176 * from all of the container child iterables stored in {@link org.opendaylight.yangtools.yang.data.api.schema.OrderedNodeContainer#getValue()}
178 * The reason why is this method called recursively is that in background method calls {@link TreeNodeFactory#createTreeNodeRecursively}
179 * for each child stored in NormalizedNode and after each child is created the method calls again {@link #createNormalizedNodeRecursively} method
180 * until all of the children are resolved.
182 * @param version version of indexed data
183 * @param container Ordered Node Container
184 * @return Normalized Ordered Container as root and all whole subtree created from container iterables.
186 public static ContainerNode createOrderedNodeRecursively(final Version version,
187 final OrderedNodeContainer<NormalizedNode<?, ?>> container) {
188 return createNodeRecursively(version, container, container.getValue());
192 * Creates and returns single instance of Normalized Node Container with provided version and data reference stored in NormalizedNodeContainer.
194 * @param version version of indexed data
195 * @param container Normalized Node Container
196 * @return single instance of Normalized node with provided version and data reference stored in NormalizedNodeContainer
198 public static ContainerNode createNormalizedNode(final Version version,
199 final NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> container) {
200 return createNode(version, container);
204 * Creates and returns single instance of Ordered Node Container with provided version and data reference stored in OrderedNodeContainer.
206 * @param version version of indexed data
207 * @param container Ordered Node Container
208 * @return single instance of Ordered Node Container with provided version and data reference stored in OrderedNodeContainer.
210 public static ContainerNode createOrderedNode(final Version version,
211 final OrderedNodeContainer<NormalizedNode<?, ?>> container) {
212 return createNode(version, container);
216 * Creates and returns single instance of {@link ContainerNode} with provided version and data reference stored in NormalizedNode.
218 * @param version version of indexed data
219 * @param data NormalizedNode data container
220 * @return single instance of {@link ContainerNode} with provided version and data reference stored in NormalizedNode.
222 private static ContainerNode createNode(final Version version, final NormalizedNode<?, ?> data) {
223 final Map<PathArgument, TreeNode> map = new HashMap<>();
224 return new ContainerNode(data, version, map, version);