import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.dom.api.DOMSchemaService;
import org.opendaylight.netconf.api.capability.Capability;
import org.opendaylight.netconf.api.monitoring.CapabilityListener;
import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
+// Non-final for mocking
public class CurrentSchemaContext implements EffectiveModelContextListener, AutoCloseable {
private final AtomicReference<EffectiveModelContext> currentContext = new AtomicReference<>();
private final ListenerRegistration<?> schemaContextListenerListenerRegistration;
private final Set<CapabilityListener> listeners1 = Collections.synchronizedSet(new HashSet<>());
private final SchemaSourceProvider<YangTextSchemaSource> rootSchemaSourceProvider;
- public EffectiveModelContext getCurrentContext() {
- checkState(currentContext.get() != null, "Current context not received");
- return currentContext.get();
- }
-
public CurrentSchemaContext(final DOMSchemaService schemaService,
final SchemaSourceProvider<YangTextSchemaSource> rootSchemaSourceProvider) {
this.rootSchemaSourceProvider = rootSchemaSourceProvider;
schemaContextListenerListenerRegistration = schemaService.registerSchemaContextListener(this);
}
+ public @NonNull EffectiveModelContext getCurrentContext() {
+ final var ret = currentContext.get();
+ checkState(ret != null, "Current context not received");
+ return ret;
+ }
+
@Override
public void onModelContextUpdated(final EffectiveModelContext schemaContext) {
currentContext.set(schemaContext);
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Iterator;
-import java.util.Optional;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.dom.DOMSource;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.netconf.api.DocumentedException;
import org.opendaylight.netconf.api.NetconfDocumentedException;
import org.opendaylight.netconf.api.xml.XmlElement;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaTreeInference;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger LOG = LoggerFactory.getLogger(AbstractEdit.class);
private static final String TARGET_KEY = "target";
- protected final CurrentSchemaContext schemaContext;
+ final CurrentSchemaContext schemaContext;
- protected AbstractEdit(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext) {
+ AbstractEdit(final String netconfSessionIdForReporting, final CurrentSchemaContext schemaContext) {
super(netconfSessionIdForReporting);
this.schemaContext = schemaContext;
}
- protected void parseIntoNormalizedNode(final DataSchemaNode schemaNode, final XmlElement element,
- final NormalizedNodeStreamWriter writer) throws DocumentedException {
+ static final void parseIntoNormalizedNode(final SchemaTreeInference inference, final XmlElement element,
+ final NormalizedNodeStreamWriter writer) throws DocumentedException {
+ final var path = inference.statementPath();
+ final var schemaNode = path.get(path.size() - 1);
if (!(schemaNode instanceof ContainerSchemaNode) && !(schemaNode instanceof ListSchemaNode)) {
// This should never happen since any edit operation on any other node type
// should not be possible nor makes sense
throw new UnsupportedOperationException("implement exception if parse fails");
}
- final XmlParserStream xmlParser = XmlParserStream.create(writer, SchemaInferenceStack.ofInstantiatedPath(
- schemaContext.getCurrentContext(), schemaNode.getPath()).toInference());
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, inference);
try {
xmlParser.traverse(new DOMSource(element.getDomElement()));
} catch (final XMLStreamException | URISyntaxException | IOException | SAXException ex) {
}
}
- protected DataSchemaNode getSchemaNodeFromNamespace(final String namespace, final XmlElement element)
- throws DocumentedException {
- final Iterator<? extends Module> it;
+ final SchemaTreeInference getSchemaNodeFromNamespace(final String namespace, final XmlElement element)
+ throws DocumentedException {
+ final XMLNamespace ns;
try {
- // Returns module with newest revision since findModuleByNamespace returns a set of modules and we only
- // need the newest one
- it = schemaContext.getCurrentContext().findModules(XMLNamespace.of(namespace)).iterator();
+ ns = XMLNamespace.of(namespace);
} catch (final IllegalArgumentException e) {
throw new NetconfDocumentedException("Unable to create URI for namespace : " + namespace, e,
ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, ErrorSeverity.ERROR);
}
+ // Returns module with newest revision since findModuleByNamespace returns a set of modules and we only
+ // need the newest one
+ final EffectiveModelContext ctx = schemaContext.getCurrentContext();
+ final Iterator<? extends @NonNull Module> it = ctx.findModules(ns).iterator();
if (!it.hasNext()) {
// No module is present with this namespace
throw new NetconfDocumentedException("Unable to find module by namespace: " + namespace,
}
final Module module = it.next();
+ final SchemaInferenceStack stack = SchemaInferenceStack.of(ctx);
final String elementName = element.getName();
- final Optional<DataSchemaNode> schemaNode = module.findDataChildByName(QName.create(module.getQNameModule(),
- element.getName()));
- if (schemaNode.isEmpty()) {
+ try {
+ // FIXME: This is a bit suspect. The element is formed using XML encoding, hence it corresponds to
+ // enterDataTree(). But then we use the result of this method to create a NormalizedNode tree,
+ // which contains ChoiceNode. This needs to be tested with something like to following:
+ //
+ // module mod {
+ // choice foo {
+ // case bar {
+ // leaf baz {
+ // type string;
+ // }
+ // }
+ // }
+ // }
+ stack.enterSchemaTree(QName.create(module.getQNameModule(), elementName));
+ } catch (IllegalArgumentException e) {
throw new DocumentedException(
- "Unable to find node " + elementName + " with namespace: " + namespace + " in module: " + module,
+ "Unable to find node " + elementName + " with namespace: " + namespace + " in module: " + module, e,
ErrorType.APPLICATION, ErrorTag.UNKNOWN_NAMESPACE, ErrorSeverity.ERROR);
}
- return schemaNode.get();
+ return stack.toSchemaTreeInference();
}
- protected static XmlElement extractTargetElement(final XmlElement operationElement, final String operationName)
+ static final XmlElement extractTargetElement(final XmlElement operationElement, final String operationName)
throws DocumentedException {
final NodeList elementsByTagName = getElementsByTagName(operationElement, TARGET_KEY);
// Direct lookup instead of using XmlElement class due to performance
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.w3c.dom.Document;
// Then create nodes present in the <config> element:
for (final XmlElement element : configElements) {
- final String ns = element.getNamespace();
- final DataSchemaNode schemaNode = getSchemaNodeFromNamespace(ns, element);
final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
- parseIntoNormalizedNode(schemaNode, element, ImmutableNormalizedNodeStreamWriter.from(resultHolder));
+ parseIntoNormalizedNode(getSchemaNodeFromNamespace(element.getNamespace(), element), element,
+ ImmutableNormalizedNodeStreamWriter.from(resultHolder));
final NormalizedNode data = resultHolder.getResult();
final YangInstanceIdentifier path = YangInstanceIdentifier.create(data.getIdentifier());
// Doing merge instead of put to support top-level list:
final XmlElement configElement = getConfigElement(operationElement);
for (final XmlElement element : configElement.getChildElements()) {
- final String ns = element.getNamespace();
- final DataSchemaNode schemaNode = getSchemaNodeFromNamespace(ns, element);
-
final SplittingNormalizedNodeMetadataStreamWriter writer = new SplittingNormalizedNodeMetadataStreamWriter(
defaultAction);
- parseIntoNormalizedNode(schemaNode, element, writer);
+ parseIntoNormalizedNode(getSchemaNodeFromNamespace(element.getNamespace(), element), element, writer);
executeOperations(writer.getDataTreeChanges());
}
import org.opendaylight.yangtools.yang.data.impl.schema.SchemaOrderedNormalizedNodeWriter;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
import org.slf4j.Logger;
return XmlUtil.createElement(document, XmlNetconfConstants.OK,
Optional.of(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0));
}
- return transformNormalizedNode(document, result.getResult(), rpcDefinition.getOutput().getPath());
+ return transformNormalizedNode(document, result.getResult(),
+ Absolute.of(rpcDefinition.getQName(), rpcDefinition.getOutput().getQName()));
}
@Override
}
private Element transformNormalizedNode(final Document document, final NormalizedNode data,
- final SchemaPath rpcOutputPath) {
+ final Absolute rpcOutputPath) {
final DOMResult result = new DOMResult(document.createElement(XmlNetconfConstants.RPC_REPLY_KEY));
final XMLStreamWriter xmlWriter = getXmlStreamWriter(result);
final NormalizedNodeStreamWriter nnStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,
schemaContext.getCurrentContext(), rpcOutputPath);
- final SchemaOrderedNormalizedNodeWriter nnWriter =
- new SchemaOrderedNormalizedNodeWriter(nnStreamWriter, schemaContext.getCurrentContext(), rpcOutputPath);
+ final SchemaOrderedNormalizedNodeWriter nnWriter = new SchemaOrderedNormalizedNodeWriter(nnStreamWriter,
+ schemaContext.getCurrentContext(), rpcOutputPath.asSchemaPath());
writeRootElement(xmlWriter, nnWriter, (ContainerNode) data);
try {
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
builder.node(child.getName());
path.add(child.getName().getLocalName());
if (child.getType() == Type.LIST) {
- appendKeyIfPresent(child, filterContent, path, builder);
+ appendKeyIfPresent(current, child, filterContent, path, builder);
return builder.build();
}
current = child;
return builder.build();
}
- private void appendKeyIfPresent(final FilterTree tree, final XmlElement filterContent,
- final List<String> pathToList,
- final InstanceIdentifierBuilder builder) {
- Preconditions.checkArgument(tree.getSchemaNode() instanceof ListSchemaNode);
- final ListSchemaNode listSchemaNode = (ListSchemaNode) tree.getSchemaNode();
+ private void appendKeyIfPresent(final FilterTree parent, final FilterTree list, final XmlElement filterContent,
+ final List<String> pathToList, final InstanceIdentifierBuilder builder) {
+ Preconditions.checkArgument(list.getSchemaNode() instanceof ListSchemaNode);
+ final ListSchemaNode listSchemaNode = (ListSchemaNode) list.getSchemaNode();
+ final DataSchemaNode parentSchemaNode = parent.getSchemaNode();
- final Map<QName, Object> map = getKeyValues(pathToList, filterContent, listSchemaNode);
+ final Map<QName, Object> map = getKeyValues(pathToList, filterContent, parentSchemaNode, listSchemaNode);
if (!map.isEmpty()) {
- builder.nodeWithKey(tree.getName(), map);
+ builder.nodeWithKey(list.getName(), map);
}
}
private Map<QName, Object> getKeyValues(final List<String> path, final XmlElement filterContent,
- final ListSchemaNode listSchemaNode) {
+ final DataSchemaNode parentSchemaNode, final ListSchemaNode listSchemaNode) {
XmlElement current = filterContent;
//find list element
for (final String pathElement : path) {
final NamespaceContext nsContext = new UniversalNamespaceContextImpl(document, false);
final EffectiveModelContext modelContext = schemaContext.getCurrentContext();
final XmlCodecFactory xmlCodecFactory = XmlCodecFactory.create(modelContext);
- final TypeAwareCodec<?, NamespaceContext, XMLStreamWriter> typeCodec = xmlCodecFactory.codecFor(
- listKey, SchemaInferenceStack.ofInstantiatedPath(modelContext, listKey.getPath()));
+ final SchemaInferenceStack resolver = SchemaInferenceStack.of(modelContext, Absolute.of(
+ parentSchemaNode.getQName(), listSchemaNode.getQName(), listKey.getQName()));
+ final TypeAwareCodec<?, NamespaceContext, XMLStreamWriter> typeCodec = xmlCodecFactory
+ .codecFor(listKey, resolver);
final Object deserializedKeyValue = typeCodec.parseValue(nsContext, keyValue.get());
keys.put(qualifiedName, deserializedKeyValue);
} else {