*/
package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
-import java.util.List;
+import java.util.Collection;
+import java.util.LinkedHashMap;
import java.util.Map;
-
+import java.util.Map.Entry;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataValidationException;
import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerNode;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class ImmutableMapEntryNodeBuilder
- extends AbstractImmutableDataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> {
-
- protected final Map<QName, InstanceIdentifier.PathArgument> childrenQNamesToPaths;
+ extends AbstractImmutableDataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> {
+ private static final Logger LOG = LoggerFactory.getLogger(ImmutableMapEntryNodeBuilder.class);
+ protected final Map<QName, PathArgument> childrenQNamesToPaths;
protected ImmutableMapEntryNodeBuilder() {
- this.childrenQNamesToPaths = Maps.newLinkedHashMap();
+ this.childrenQNamesToPaths = new LinkedHashMap<>();
+ }
+
+ protected ImmutableMapEntryNodeBuilder(final int sizeHint) {
+ super(sizeHint);
+ this.childrenQNamesToPaths = new LinkedHashMap<>(sizeHint);
+ }
+
+ protected ImmutableMapEntryNodeBuilder(final ImmutableMapEntryNode node) {
+ super(node);
+ this.childrenQNamesToPaths = new LinkedHashMap<>();
+ fillQnames(node.body(), childrenQNamesToPaths);
}
- public static DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> create() {
+ public static @NonNull DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> create() {
return new ImmutableMapEntryNodeBuilder();
}
- // FIXME, find better solution than 2 maps (map from QName to Child ?)
+ public static @NonNull DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> create(
+ final int sizeHint) {
+ return new ImmutableMapEntryNodeBuilder(sizeHint);
+ }
- @Override
- public DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> withValue(final List<DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> value) {
- for (DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> childId : value) {
- this.childrenQNamesToPaths.put(childId.getNodeType(), childId.getIdentifier());
+ public static @NonNull DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> create(
+ final MapEntryNode node) {
+ if (!(node instanceof ImmutableMapEntryNode)) {
+ throw new UnsupportedOperationException(String.format("Cannot initialize from class %s", node.getClass()));
}
- return super.withValue(value);
+
+ return new ImmutableMapEntryNodeBuilder((ImmutableMapEntryNode)node);
}
- @Override
- public DataContainerNodeBuilder<InstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> withChild(final DataContainerChild<?, ?> child) {
- childrenQNamesToPaths.put(child.getNodeType(), child.getIdentifier());
- return super.withChild(child);
+ private static void fillQnames(final Iterable<DataContainerChild> iterable, final Map<QName, PathArgument> out) {
+ for (final DataContainerChild childId : iterable) {
+ final PathArgument identifier = childId.getIdentifier();
+
+ // Augmentation nodes cannot be keys, and do not have to be present in childrenQNamesToPaths map
+ if (isAugment(identifier)) {
+ continue;
+ }
+
+ out.put(childId.getNodeType(), identifier);
+ }
}
@Override
- public MapEntryNode build() {
- checkKeys();
- return new ImmutableMapEntryNode(nodeIdentifier, value);
+ public DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> withValue(
+ final Collection<DataContainerChild> withValue) {
+ fillQnames(withValue, childrenQNamesToPaths);
+ return super.withValue(withValue);
}
- private void checkKeys() {
- for (QName keyQName : nodeIdentifier.getKeyValues().keySet()) {
+ private static boolean isAugment(final PathArgument identifier) {
+ return identifier instanceof AugmentationIdentifier;
+ }
- InstanceIdentifier.PathArgument childNodePath = childrenQNamesToPaths.get(keyQName);
- DataContainerChild<?, ?> childNode = value.get(childNodePath);
+ @Override
+ public DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> withChild(
+ final DataContainerChild child) {
+ // Augmentation nodes cannot be keys, and do not have to be present in childrenQNamesToPaths map
+ if (!isAugment(child.getIdentifier())) {
+ childrenQNamesToPaths.put(child.getNodeType(), child.getIdentifier());
+ }
- Preconditions.checkNotNull(childNode, "Key child node: %s, not present", keyQName);
+ return super.withChild(child);
+ }
- Object actualValue = nodeIdentifier.getKeyValues().get(keyQName);
- Object expectedValue = childNode.getValue();
- Preconditions.checkArgument(expectedValue.equals(actualValue),
- "Key child node with unexpected value, is: %s, should be: %s", actualValue, expectedValue);
+ @Override
+ public MapEntryNode build() {
+ for (final Entry<QName, Object> key : getNodeIdentifier().entrySet()) {
+ final DataContainerChild childNode = getChild(childrenQNamesToPaths.get(key.getKey()));
+
+ // We have enough information to fill-in missing leaf nodes, so let's do that
+ if (childNode == null) {
+ LeafNode<Object> leaf = ImmutableNodes.leafNode(key.getKey(), key.getValue());
+ LOG.debug("Adding leaf {} implied by key {}", leaf, key);
+ withChild(leaf);
+ } else {
+ DataValidationException.checkListKey(getNodeIdentifier(), key.getKey(), key.getValue(),
+ childNode.body());
+ }
}
+
+ return new ImmutableMapEntryNode(getNodeIdentifier(), buildValue());
}
- static final class ImmutableMapEntryNode extends AbstractImmutableDataContainerNode<InstanceIdentifier.NodeIdentifierWithPredicates> implements MapEntryNode {
+ private static final class ImmutableMapEntryNode
+ extends AbstractImmutableDataContainerNode<NodeIdentifierWithPredicates, MapEntryNode>
+ implements MapEntryNode {
+
+ ImmutableMapEntryNode(final NodeIdentifierWithPredicates nodeIdentifier,
+ final Map<PathArgument, Object> children) {
+ super(children, nodeIdentifier);
+ }
- ImmutableMapEntryNode(final InstanceIdentifier.NodeIdentifierWithPredicates nodeIdentifier,
- final Map<InstanceIdentifier.PathArgument, DataContainerChild<? extends InstanceIdentifier.PathArgument, ?>> children) {
- super(ImmutableMap.copyOf(children), nodeIdentifier);
+ @Override
+ protected Class<MapEntryNode> implementedType() {
+ return MapEntryNode.class;
}
}
}