*/
package org.opendaylight.yangtools.yang.data.api.schema.tree.spi;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
import java.util.HashMap;
import java.util.Map;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
import org.opendaylight.yangtools.yang.data.api.schema.OrderedNodeContainer;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
/**
* A TreeNode capable of holding child nodes. The fact that any of the children
* changed is tracked by the subtree version.
*/
-final class ContainerNode extends AbstractTreeNode {
- private final Map<PathArgument, TreeNode> children;
+abstract class ContainerNode extends AbstractTreeNode {
private final Version subtreeVersion;
- protected ContainerNode(final NormalizedNode<?, ?> data, final Version version,
- final Map<PathArgument, TreeNode> children, final Version subtreeVersion) {
+ protected ContainerNode(final NormalizedNode<?, ?> data, final Version version, final Version subtreeVersion) {
super(data, version);
- this.children = Preconditions.checkNotNull(children);
this.subtreeVersion = Preconditions.checkNotNull(subtreeVersion);
}
@Override
- public Version getSubtreeVersion() {
+ public final Version getSubtreeVersion() {
return subtreeVersion;
}
- @Override
- public Optional<TreeNode> getChild(final PathArgument key) {
- Optional<TreeNode> explicitNode = Optional.fromNullable(children.get(key));
- if (explicitNode.isPresent()) {
- return explicitNode;
- }
- final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> castedData = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>>) getData();
- Optional<NormalizedNode<?, ?>> value = castedData.getChild(key);
- if (value.isPresent()) {
- //FIXME: consider caching created Tree Nodes.
- //We are safe to not to cache them, since written Tree Nodes are in read only snapshot.
- return Optional.of(TreeNodeFactory.createTreeNode(value.get(), getVersion()));
- }
- return Optional.absent();
- }
-
- @Override
- public MutableTreeNode mutable() {
- return new Mutable(this);
- }
-
- private static final class Mutable implements MutableTreeNode {
+ protected static final class Mutable implements MutableTreeNode {
private final Version version;
private Map<PathArgument, TreeNode> children;
private NormalizedNode<?, ?> data;
private Version subtreeVersion;
- private Mutable(final ContainerNode parent) {
+ Mutable(final ContainerNode parent, final Map<PathArgument, TreeNode> children) {
this.data = parent.getData();
- this.children = MapAdaptor.getDefaultInstance().takeSnapshot(parent.children);
- this.subtreeVersion = parent.getSubtreeVersion();
this.version = parent.getVersion();
- materializeChildVersion();
- }
-
- /**
- * Traverse whole data tree and instantiate children for each data node. Set version of each MutableTreeNode
- * accordingly to version in data node.
- *
- * Use this method if TreeNode is lazy initialized.
- */
- private void materializeChildVersion() {
- Preconditions.checkState(data instanceof NormalizedNodeContainer);
- NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> castedData = (NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>>) data;
-
- for(NormalizedNode<?, ?> childData : castedData.getValue()) {
- PathArgument id = childData.getIdentifier();
-
- if (!children.containsKey(id)) {
- children.put(id, TreeNodeFactory.createTreeNode(childData, version));
- }
- }
+ this.subtreeVersion = parent.getSubtreeVersion();
+ this.children = Preconditions.checkNotNull(children);
}
@Override
@Override
public TreeNode seal() {
- final TreeNode ret = new ContainerNode(data, version, MapAdaptor.getDefaultInstance().optimize(children), subtreeVersion);
+ final TreeNode ret = new MaterializedContainerNode(data, version, MapAdaptor.getDefaultInstance().optimize(children), subtreeVersion);
// This forces a NPE if this class is accessed again. Better than corruption.
children = null;
map.put(child.getIdentifier(), TreeNodeFactory.createTreeNodeRecursively(child, version));
}
- return new ContainerNode(data, version, map, version);
+ return new MaterializedContainerNode(data, version, map, version);
}
/**
*/
public static ContainerNode createNormalizedNode(final Version version,
final NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> container) {
- return createNode(version, container);
+ return new LazyContainerNode(container, version);
}
/**
*/
public static ContainerNode createOrderedNode(final Version version,
final OrderedNodeContainer<NormalizedNode<?, ?>> container) {
- return createNode(version, container);
- }
-
- /**
- * Creates and returns single instance of {@link ContainerNode} with provided version and data reference stored in NormalizedNode.
- *
- * @param version version of indexed data
- * @param data NormalizedNode data container
- * @return single instance of {@link ContainerNode} with provided version and data reference stored in NormalizedNode.
- */
- private static ContainerNode createNode(final Version version, final NormalizedNode<?, ?> data) {
- final Map<PathArgument, TreeNode> map = new HashMap<>();
- return new ContainerNode(data, version, map, version);
+ return new LazyContainerNode(container, version);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.api.schema.tree.spi;
+
+import com.google.common.base.Optional;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
+
+final class LazyContainerNode extends ContainerNode {
+ protected LazyContainerNode(final NormalizedNode<?, ?> data, final Version version) {
+ super(data, version, version);
+ }
+
+ @Override
+ public Optional<TreeNode> getChild(final PathArgument key) {
+ // We do not cache the instantiated node as it is dirt cheap
+ final Optional<NormalizedNode<?, ?>> child = castData().getChild(key);
+ if (child.isPresent()) {
+ return Optional.of(TreeNodeFactory.createTreeNode(child.get(), getVersion()));
+ }
+
+ return Optional.absent();
+ }
+
+ @Override
+ public MutableTreeNode mutable() {
+ /*
+ * We are creating a mutable view of the data, which means that the version
+ * is going to probably change -- and we need to make sure any unmodified
+ * children retain it.
+ *
+ * The simplest thing to do is to just flush the amortized work and be done
+ * with it.
+ */
+ final Map<PathArgument, TreeNode> children = new HashMap<>();
+ for (NormalizedNode<?, ?> child : castData().getValue()) {
+ PathArgument id = child.getIdentifier();
+ children.put(id, TreeNodeFactory.createTreeNode(child, getVersion()));
+ }
+
+ return new Mutable(this, children);
+ }
+
+ @SuppressWarnings("unchecked")
+ private final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> castData() {
+ return (NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>>) getData();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 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.api.schema.tree.spi;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+import java.util.Map;
+
+import org.opendaylight.yangtools.util.MapAdaptor;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+final class MaterializedContainerNode extends ContainerNode {
+ private final Map<PathArgument, TreeNode> children;
+
+ protected MaterializedContainerNode(final NormalizedNode<?, ?> data, final Version version,
+ final Map<PathArgument, TreeNode> children, final Version subtreeVersion) {
+ super(data, version, subtreeVersion);
+ this.children = Preconditions.checkNotNull(children);
+ }
+
+ @Override
+ public Optional<TreeNode> getChild(final PathArgument key) {
+ return Optional.fromNullable(children.get(key));
+ }
+
+ @Override
+ public MutableTreeNode mutable() {
+ return new Mutable(this, MapAdaptor.getDefaultInstance().takeSnapshot(children));
+ }
+}