package org.opendaylight.yangtools.yang.data.util;
import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Verify.verify;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.Map;
+import org.opendaylight.yangtools.util.ImmutableMapTemplate;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamAttributeWriter;
* Represents a YANG list entry node.
*/
public class ListEntryNodeDataWithSchema extends CompositeNodeDataWithSchema {
+ // This template results in Maps in schema definition order
+ private final ImmutableMapTemplate<QName> predicateTemplate;
+ private final Map<QName, SimpleNodeDataWithSchema> keyValues;
- private final Map<QName, SimpleNodeDataWithSchema> qnameToKeys = new HashMap<>();
-
+ // FIXME: 3.0.0: require ListSchemaNode
+ // FIXME: 3.0.0: hide this constructor and provide specialized keyed/unkeyed classes
public ListEntryNodeDataWithSchema(final DataSchemaNode schema) {
super(schema);
+
+ final Collection<QName> keyDef = ((ListSchemaNode) getSchema()).getKeyDefinition();
+ if (keyDef.isEmpty()) {
+ predicateTemplate = null;
+ keyValues = null;
+ } else {
+ predicateTemplate = ImmutableMapTemplate.ordered(keyDef);
+ keyValues = new HashMap<>();
+ }
}
@Override
public void addChild(final AbstractNodeDataWithSchema newChild) {
- final DataSchemaNode childSchema = newChild.getSchema();
- if (childSchema instanceof LeafSchemaNode && isPartOfKey((LeafSchemaNode) childSchema)) {
- qnameToKeys.put(childSchema.getQName(), (SimpleNodeDataWithSchema)newChild);
+ if (predicateTemplate != null) {
+ final DataSchemaNode childSchema = newChild.getSchema();
+ if (childSchema instanceof LeafSchemaNode) {
+ populateKeyValue(childSchema.getQName(), newChild);
+ }
}
super.addChild(newChild);
}
- private boolean isPartOfKey(final LeafSchemaNode potentialKey) {
- for (QName qname : ((ListSchemaNode) getSchema()).getKeyDefinition()) {
- if (qname.equals(potentialKey.getQName())) {
- return true;
- }
+ private void populateKeyValue(final QName childName, final AbstractNodeDataWithSchema child) {
+ if (predicateTemplate.keySet().contains(childName)) {
+ verify(child instanceof SimpleNodeDataWithSchema);
+ keyValues.put(childName, (SimpleNodeDataWithSchema)child);
}
- return false;
}
@Override
public void write(final NormalizedNodeStreamWriter writer) throws IOException {
- final Collection<QName> keyDef = ((ListSchemaNode) getSchema()).getKeyDefinition();
- if (keyDef.isEmpty()) {
- writer.nextDataSchemaNode(getSchema());
+ writer.nextDataSchemaNode(getSchema());
+ if (predicateTemplate != null) {
+ writeKeyedListItem(writer);
+ } else {
writer.startUnkeyedListItem(provideNodeIdentifier(), childSizeHint());
- super.write(writer);
- writer.endNode();
- return;
}
- checkState(keyDef.size() == qnameToKeys.size(), "Input is missing some of the keys of %s",
- getSchema().getQName());
+ super.write(writer);
+ writer.endNode();
+ }
- // Need to restore schema order...
- final Map<QName, Object> predicates = new LinkedHashMap<>();
- for (QName qname : keyDef) {
- predicates.put(qname, qnameToKeys.get(qname).getValue());
- }
+ private void writeKeyedListItem(final NormalizedNodeStreamWriter writer) throws IOException {
+ // FIXME: 3.0.0: remove this check? predicateTemplate will throw an IllegalArgumentException if anything
+ // goes wrong -- which is a change of behavior, as now we're throwing an ISE. Do we want that?
+ final Collection<QName> keySet = predicateTemplate.keySet();
+ checkState(keySet.size() == keyValues.size(),
+ "Map entry corresponding to %s is missing some of required keys %s", getSchema().getQName(), keySet);
- writer.nextDataSchemaNode(getSchema());
+ final NodeIdentifierWithPredicates identifier = new NodeIdentifierWithPredicates(getSchema().getQName(),
+ predicateTemplate.instantiateTransformed(keyValues, (key, node) -> node.getValue()));
if (writer instanceof NormalizedNodeStreamAttributeWriter && getAttributes() != null) {
- ((NormalizedNodeStreamAttributeWriter) writer).startMapEntryNode(
- new NodeIdentifierWithPredicates(getSchema().getQName(), predicates), childSizeHint(),
- getAttributes());
+ ((NormalizedNodeStreamAttributeWriter) writer).startMapEntryNode(identifier, childSizeHint(),
+ getAttributes());
} else {
- writer.startMapEntryNode(new NodeIdentifierWithPredicates(getSchema().getQName(), predicates),
- childSizeHint());
+ writer.startMapEntryNode(identifier, childSizeHint());
}
-
- super.write(writer);
- writer.endNode();
}
}