/* * 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.Preconditions; import com.google.common.base.Verify; 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; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer; /** * Abstract base for container-based {@link MutableTreeNode}s. It tracks modified nodes in a map and deals with * correctly implementing {@link #seal()}. */ abstract class AbstractMutableContainerNode implements MutableTreeNode { private final Version version; private Map<PathArgument, TreeNode> children; private NormalizedNode<?, ?> data; private Version subtreeVersion; protected AbstractMutableContainerNode(final AbstractContainerNode parent, final Map<PathArgument, TreeNode> children) { this.data = parent.getData(); this.version = parent.getVersion(); this.subtreeVersion = parent.getSubtreeVersion(); this.children = Preconditions.checkNotNull(children); } protected final Version getVersion() { return version; } protected final TreeNode getModifiedChild(final PathArgument child) { return children.get(child); } @SuppressWarnings("unchecked") protected final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> getData() { return (NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>>) data; } @Override public final void setSubtreeVersion(final Version subtreeVersion) { this.subtreeVersion = Preconditions.checkNotNull(subtreeVersion); } @Override public final void addChild(final TreeNode child) { children.put(child.getIdentifier(), child); } @Override public final void removeChild(final PathArgument id) { children.remove(id); } @Override public final void setData(final NormalizedNode<?, ?> data) { this.data = Preconditions.checkNotNull(data); } @Override public final TreeNode seal() { final TreeNode ret; /* * Decide which implementation: * * => version equals subtree version, this node has not been updated since its creation * => children.size() equals data child size, this node has been completely materialized and further lookups * into data will not happen, * => more materialization can happen */ if (!version.equals(subtreeVersion)) { final Map<PathArgument, TreeNode> newChildren = MapAdaptor.getDefaultInstance().optimize(children); final int dataSize = getData().getValue().size(); if (dataSize != newChildren.size()) { Verify.verify(dataSize > newChildren.size(), "Detected %s modified children, data has only %s", newChildren.size(), dataSize); ret = new LazyContainerNode(data, version, newChildren, subtreeVersion); } else { ret = new MaterializedContainerNode(data, version, newChildren, subtreeVersion); } } else { ret = new SimpleContainerNode(data, version); } // This forces a NPE if this class is accessed again. Better than corruption. children = null; return ret; } }