import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
+import java.util.stream.Collectors;
import javax.xml.transform.dom.DOMSource;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.common.QName;
}
@Override
- void streamToWriter(final NormalizedNodeStreamWriter writer, final PathArgument first,
- final PathNode subtree) throws IOException {
+ final void streamToWriter(final NormalizedNodeStreamWriter writer, final PathArgument first,
+ final PathNode subtree) throws IOException {
verifyActualPathArgument(first);
emitElementStart(writer, first);
for (final PathNode node : subtree.children()) {
- final PathArgument childPath = node.element();
- final StreamingContext<?> childOp = getChildOperation(childPath);
- childOp.streamToWriter(writer, childPath, node);
+ emitChildTreeNode(writer, node);
}
writer.endNode();
}
+ void emitChildTreeNode(final NormalizedNodeStreamWriter writer, final PathNode node) throws IOException {
+ final PathArgument childPath = node.element();
+ getChildOperation(childPath).streamToWriter(writer, childPath, node);
+ }
+
private void verifyActualPathArgument(final PathArgument first) {
if (!isMixin()) {
final QName type = getIdentifier().getNodeType();
abstract void emitElementStart(NormalizedNodeStreamWriter writer, PathArgument arg) throws IOException;
@SuppressWarnings("checkstyle:illegalCatch")
- private StreamingContext<?> getChildOperation(final PathArgument childPath) {
+ StreamingContext<?> getChildOperation(final PathArgument childPath) {
final StreamingContext<?> childOp;
try {
childOp = getChild(childPath);
private abstract static class AbstractMapMixin extends AbstractComposite<NodeIdentifier> {
private final ListEntry innerNode;
+ private final List<QName> keyLeaves;
AbstractMapMixin(final ListSchemaNode list) {
super(NodeIdentifier.create(list.getQName()));
this.innerNode = new ListEntry(NodeIdentifierWithPredicates.of(list.getQName()), list);
+ this.keyLeaves = list.getKeyDefinition();
}
@Override
final boolean isMixin() {
return true;
}
+
+ @Override
+ final void emitChildTreeNode(final NormalizedNodeStreamWriter writer, final PathNode node) throws IOException {
+ final NodeIdentifierWithPredicates childPath = (NodeIdentifierWithPredicates) node.element();
+ final StreamingContext<?> childOp = getChildOperation(childPath);
+ if (childPath.size() == 0 && node.isEmpty() || childPath.keySet().containsAll(keyLeaves)) {
+ // This is a query for the entire list, or the query specifies everything we need
+ childOp.streamToWriter(writer, childPath, node);
+ return;
+ }
+
+ // Inexact query, we need to also request the leaf nodes we need to for reconstructing a valid instance
+ // NodeIdentifierWithPredicates.
+ childOp.streamToWriter(writer, childPath, node.copyWith(keyLeaves.stream()
+ .filter(qname -> !childPath.containsKey(qname))
+ .map(NodeIdentifier::new)
+ .collect(Collectors.toUnmodifiableList())));
+ }
}
private abstract static class AbstractSimple<T extends PathArgument> extends StreamingContext<T> {
}
@Override
- void streamToWriter(final NormalizedNodeStreamWriter writer, final PathArgument first,
+ final void streamToWriter(final NormalizedNodeStreamWriter writer, final PathArgument first,
final PathNode tree) throws IOException {
streamToWriter(writer, first, Collections.emptyIterator());
}
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Statistics;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.datastores.Datastore;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.datastores.datastore.Locks;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.datastores.datastore.locks.lock.type.partial.lock.PartialLock;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas.Schema;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions.Session;
import org.opendaylight.yangtools.rcf8528.data.util.EmptyMountPointContext;
final YangInstanceIdentifier versionField = YangInstanceIdentifier.create(
toId(QName.create(Schema.QNAME, "version").intern()));
final YangInstanceIdentifier identifierField = YangInstanceIdentifier.create(
- toId(QName.create(Schema.QNAME, "identifier").intern()));
+ toId(QName.create(Schema.QNAME, "namespace").intern()));
// building filter structure and NETCONF message
final DataContainerChild<?, ?> filterStructure = toFilterStructure(Collections.singletonList(FieldsFilter.of(
+ "<schemas>\n"
+ "<schema>\n"
+ "<version/>\n"
+ + "<namespace/>\n"
+ // explicitly fetched list keys - identifier and format
+ "<identifier/>\n"
+ + "<format/>\n"
+ "</schema>\n"
+ "</schemas>\n"
+ "</netconf-state>\n"
+ "</rpc>");
}
+ @Test
+ public void getSpecificFieldsUnderMultipleLists() throws IOException, SAXException {
+ // preparation of the fields
+ final YangInstanceIdentifier parentYiid = YangInstanceIdentifier.create(
+ toId(NetconfState.QNAME), toId(Datastores.QNAME));
+ final YangInstanceIdentifier partialLockYiid = YangInstanceIdentifier.create(toId(Datastore.QNAME),
+ NodeIdentifierWithPredicates.of(Datastore.QNAME), toId(Locks.QNAME),
+ toId(QName.create(Locks.QNAME, "lock-type").intern()), toId(PartialLock.QNAME),
+ NodeIdentifierWithPredicates.of(PartialLock.QNAME));
+ final YangInstanceIdentifier lockedTimeField = partialLockYiid.node(
+ QName.create(Locks.QNAME, "locked-time").intern());
+ final YangInstanceIdentifier lockedBySessionField = partialLockYiid.node(
+ QName.create(Locks.QNAME, "locked-by-session").intern());
+
+ // building filter structure and NETCONF message
+ final DataContainerChild<?, ?> filterStructure = toFilterStructure(Collections.singletonList(FieldsFilter.of(
+ parentYiid, List.of(lockedTimeField, lockedBySessionField))), SCHEMA);
+ final NetconfMessage netconfMessage = netconfMessageTransformer.toRpcRequest(NETCONF_GET_QNAME,
+ NetconfMessageTransformUtil.wrap(toId(NETCONF_GET_QNAME), filterStructure));
+
+ // testing
+ assertSimilarXml(netconfMessage, "<rpc message-id=\"m-0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+ + "<get>\n"
+ + "<filter xmlns:ns0=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ns0:type=\"subtree\">\n"
+ + "<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\">\n"
+ + "<datastores>\n"
+ + "<datastore>\n"
+ + "<locks>\n"
+ + "<partial-lock>\n"
+ + "<locked-time/>\n"
+ + "<locked-by-session/>\n"
+ + "<lock-id/>\n"
+ + "</partial-lock>\n"
+ + "</locks>\n"
+ + "<name/>\n"
+ + "</datastore>\n"
+ + "</datastores>\n"
+ + "</netconf-state>\n"
+ + "</filter>\n"
+ + "</get>\n"
+ + "</rpc>");
+ }
+
@Test
public void getWholeListsUsingFieldsTest() throws IOException, SAXException {
// preparation of the fields