Optimize LazyContainerNode.getChild()
[yangtools.git] / yang / yang-data-api / src / main / java / org / opendaylight / yangtools / yang / data / api / schema / tree / spi / LazyContainerNode.java
index a2bc1cbc99b4fa3d3919c50f69dcfd44cc6c06c5..6c877dce218bacdbda8926e2366f1cce44f2487a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ * 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,
@@ -7,52 +7,47 @@
  */
 package org.opendaylight.yangtools.yang.data.api.schema.tree.spi;
 
-import com.google.common.base.Optional;
-
-import java.util.HashMap;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.Collections2;
 import java.util.Map;
-
+import java.util.Optional;
+import org.opendaylight.yangtools.util.MapAdaptor;
 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);
+/**
+ * Lazily-materialized container node. Any new/modified children are tracked in a map. This map is consulted before
+ * instantiating a child node from data node. Resulting node is not cached.
+ */
+final class LazyContainerNode extends AbstractModifiedContainerNode {
+    LazyContainerNode(final NormalizedNode<?, ?> data, final Version version, final Version subtreeVersion) {
+        this(data, version, MapAdaptor.getDefaultInstance().initialSnapshot(1), subtreeVersion);
     }
 
-    @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();
+    LazyContainerNode(final NormalizedNode<?, ?> data, final Version version,
+            final Map<PathArgument, TreeNode> children, final Version subtreeVersion) {
+        super(data, version, children, subtreeVersion);
     }
 
     @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()));
+        final Map<PathArgument, TreeNode> snapshot = snapshotChildren();
+        if (snapshot.size() == castData().size()) {
+            return new MaterializedMutableContainerNode(this, snapshot);
         }
+        return new LazyMutableContainerNode(this, snapshot);
+    }
 
-        return new Mutable(this, children);
+    @Override
+    public Optional<TreeNode> getChild(final PathArgument childId) {
+        final TreeNode modified;
+        return (modified = getModifiedChild(childId)) == null ? getChildFromData(childId) : Optional.of(modified);
     }
 
-    @SuppressWarnings("unchecked")
-    private final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> castData() {
-        return (NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>>) getData();
+    @Override
+    protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+        // Modified children add added by superclass. Here we filter the other children.
+        return super.addToStringAttributes(helper).add("untouched", Collections2.filter(castData().getValue(),
+            input -> getModifiedChild(input.getIdentifier()) == null));
     }
 }