import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
+import java.io.StringReader;
import java.net.URI;
import java.net.URISyntaxException;
-import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.opendaylight.netconf.mdsal.connector.TransactionProvider;
import org.opendaylight.netconf.mdsal.connector.ops.DataTreeChangeTracker.DataTreeChange;
import org.opendaylight.netconf.util.mapping.AbstractSingletonNetconfOperation;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.ModifyAction;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
final DataSchemaNode schemaNode = getSchemaNodeFromNamespace(ns, element).get();
final DataTreeChangeTracker changeTracker = new DataTreeChangeTracker(defaultAction);
- final DomToNormalizedNodeParserFactory.BuildingStrategyProvider editOperationStrategyProvider =
- new EditOperationStrategyProvider(changeTracker);
- parseIntoNormalizedNode(schemaNode, element, editOperationStrategyProvider);
+ parseIntoNormalizedNode(schemaNode, element, changeTracker);
executeOperations(changeTracker);
}
}
}
+ @SuppressWarnings("checkstyle:IllegalCatch")
private NormalizedNode<?, ?> parseIntoNormalizedNode(final DataSchemaNode schemaNode, final XmlElement element,
- final DomToNormalizedNodeParserFactory.BuildingStrategyProvider editOperationStrategyProvider) {
- if (schemaNode instanceof ContainerSchemaNode) {
- return DomToNormalizedNodeParserFactory.getInstance(DomUtils.defaultValueCodecProvider(),
- schemaContext.getCurrentContext(), editOperationStrategyProvider)
- .getContainerNodeParser()
- .parse(Collections.singletonList(element.getDomElement()), (ContainerSchemaNode) schemaNode);
- } else if (schemaNode instanceof ListSchemaNode) {
- return DomToNormalizedNodeParserFactory.getInstance(DomUtils.defaultValueCodecProvider(),
- schemaContext.getCurrentContext(), editOperationStrategyProvider)
- .getMapNodeParser()
- .parse(Collections.singletonList(element.getDomElement()), (ListSchemaNode) schemaNode);
- } else {
+ final DataTreeChangeTracker changeTracker) throws DocumentedException {
+ if (!(schemaNode instanceof ContainerSchemaNode) && !(schemaNode instanceof ListSchemaNode)) {
//this should never happen since edit-config on any other node type should not be possible nor makes sense
LOG.debug("DataNode from module is not ContainerSchemaNode nor ListSchemaNode, aborting..");
+ throw new UnsupportedOperationException("implement exception if parse fails");
}
- throw new UnsupportedOperationException("implement exception if parse fails");
+
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = new EditOperationNormalizedNodeStreamWriter(resultHolder,
+ changeTracker);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, schemaContext.getCurrentContext(), schemaNode);
+ try {
+ xmlParser.parse(UntrustedXML.createXMLStreamReader(new StringReader(XmlUtil.toString(element))));
+ } catch (final Exception ex) {
+ throw new NetconfDocumentedException("Error parsing input: " + ex.getMessage(), ex, ErrorType.PROTOCOL,
+ ErrorTag.MALFORMED_MESSAGE, ErrorSeverity.ERROR);
+ }
+
+ return resultHolder.getResult();
}
private Optional<DataSchemaNode> getSchemaNodeFromNamespace(final String namespace, final XmlElement element)
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.netconf.mdsal.connector.ops;
+
+import java.util.ArrayList;
+import java.util.Map;
+import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.EditConfigInput;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.ModifyAction;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamAttributeWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
+
+final class EditOperationNormalizedNodeStreamWriter extends ImmutableNormalizedNodeStreamWriter
+ implements NormalizedNodeStreamAttributeWriter {
+ private static final QName OPERATION_ATTRIBUTE = QName.create(EditConfigInput.QNAME.getNamespace(), null,
+ XmlNetconfConstants.OPERATION_ATTR_KEY);
+
+ private final DataTreeChangeTracker dataTreeChangeTracker;
+
+ EditOperationNormalizedNodeStreamWriter(final NormalizedNodeResult result,
+ final DataTreeChangeTracker dataTreeChangeTracker) {
+ super(result);
+ this.dataTreeChangeTracker = dataTreeChangeTracker;
+ }
+
+ @Override
+ public void leafNode(final NodeIdentifier name, final Object value, final Map<QName, String> attributes) {
+ super.leafNode(name, value);
+
+ final String operation = attributes.get(OPERATION_ATTRIBUTE);
+ if (operation == null) {
+ return;
+ }
+
+ final ModifyAction action = ModifyAction.fromXmlValue(operation);
+ if (dataTreeChangeTracker.getDeleteOperationTracker() == 0
+ && dataTreeChangeTracker.getRemoveOperationTracker() == 0) {
+ if (!action.equals(dataTreeChangeTracker.peekAction())) {
+ final LeafNode<Object> node = ImmutableNodes.leafNode(name, value);
+ dataTreeChangeTracker.pushPath(name);
+ dataTreeChangeTracker.addDataTreeChange(new DataTreeChangeTracker.DataTreeChange(node, action,
+ new ArrayList<>(dataTreeChangeTracker.getCurrentPath())));
+ getCurrent().removeChild(dataTreeChangeTracker.popPath());
+ }
+ }
+ }
+
+ @Override
+ public void startLeafSet(final NodeIdentifier name, final int childSizeHint) {
+ super.startLeafSet(name, childSizeHint);
+ dataTreeChangeTracker.pushPath(name);
+ }
+
+ @Override
+ public void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) {
+ super.startOrderedLeafSet(name, childSizeHint);
+ dataTreeChangeTracker.pushPath(name);
+ }
+
+ @Override
+ public void leafSetEntryNode(final QName name, final Object value, final Map<QName, String> attributes) {
+ super.leafSetEntryNode(name, value);
+ final String operation = attributes.get(OPERATION_ATTRIBUTE);
+ if (operation == null) {
+ return;
+ }
+
+ ModifyAction action = ModifyAction.fromXmlValue(operation);
+ if (dataTreeChangeTracker.getDeleteOperationTracker() == 0
+ && dataTreeChangeTracker.getRemoveOperationTracker() == 0) {
+ if (!action.equals(dataTreeChangeTracker.peekAction())) {
+ final LeafSetEntryNode<?> node = Builders.leafSetEntryBuilder().withNodeIdentifier(
+ new NodeWithValue(name, value)).withValue(value).build();
+ dataTreeChangeTracker.pushPath(node.getIdentifier());
+ dataTreeChangeTracker.addDataTreeChange(new DataTreeChangeTracker.DataTreeChange(node, action,
+ new ArrayList<>(dataTreeChangeTracker.getCurrentPath())));
+ getCurrent().removeChild(dataTreeChangeTracker.popPath());
+ }
+ }
+ }
+
+ @Override
+ public void startContainerNode(final NodeIdentifier name, final int childSizeHint,
+ final Map<QName, String> attributes) {
+ super.startContainerNode(name, childSizeHint);
+ trackDataContainerNode(name, attributes);
+ }
+
+ @Override
+ public void startYangModeledAnyXmlNode(final NodeIdentifier name, final int childSizeHint,
+ final Map<QName, String> attributes) {
+ super.startYangModeledAnyXmlNode(name, childSizeHint);
+ trackDataContainerNode(name, attributes);
+ }
+
+ @Override
+ public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) {
+ super.startUnkeyedList(name, childSizeHint);
+ dataTreeChangeTracker.pushPath(name);
+ }
+
+ @Override
+ public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint,
+ final Map<QName, String> attributes) {
+ super.startUnkeyedListItem(name, childSizeHint);
+ trackDataContainerNode(name, attributes);
+ }
+
+ @Override
+ public void startMapNode(final NodeIdentifier name, final int childSizeHint) {
+ super.startMapNode(name, childSizeHint);
+ dataTreeChangeTracker.pushPath(name);
+ }
+
+ @Override
+ public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) {
+ super.startOrderedMapNode(name, childSizeHint);
+ dataTreeChangeTracker.pushPath(name);
+ }
+
+ @Override
+ public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint,
+ final Map<QName, String> attributes) {
+ super.startMapEntryNode(identifier, childSizeHint);
+ trackDataContainerNode(identifier, attributes);
+ }
+
+ @Override
+ public void startAugmentationNode(final AugmentationIdentifier identifier) {
+ super.startAugmentationNode(identifier);
+ trackMixinNode(identifier);
+ }
+
+ @Override
+ public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) {
+ super.startChoiceNode(name, childSizeHint);
+ trackMixinNode(name);
+ }
+
+ // for augments and choices
+ private void trackMixinNode(final PathArgument identifier) {
+ dataTreeChangeTracker.pushPath(identifier);
+ dataTreeChangeTracker.pushAction(dataTreeChangeTracker.peekAction() != null
+ ? dataTreeChangeTracker.peekAction() : dataTreeChangeTracker.getDefaultAction());
+ }
+
+ // for containers, (unkeyed) list entries and yang-modeled-anyxmls
+ private void trackDataContainerNode(final PathArgument identifier, final Map<QName, String> attributes) {
+ dataTreeChangeTracker.pushPath(identifier);
+ final String operation = attributes.get(OPERATION_ATTRIBUTE);
+ if (operation != null) {
+ dataTreeChangeTracker.pushAction(ModifyAction.fromXmlValue(operation));
+ } else {
+ dataTreeChangeTracker.pushAction(dataTreeChangeTracker.peekAction() != null
+ ? dataTreeChangeTracker.peekAction() : dataTreeChangeTracker.getDefaultAction());
+ }
+ }
+
+ @Override
+ @SuppressWarnings({"rawtypes","unchecked"})
+ public void endNode() {
+ final NormalizedNodeContainerBuilder finishedBuilder = getBuilders().peek();
+ final NormalizedNode<PathArgument, ?> product = finishedBuilder.build();
+ super.endNode();
+
+ // for augments, choices, containers, (unkeyed) list entries and yang-modeled-anyxmls
+ if (finishedBuilder instanceof DataContainerNodeBuilder) {
+ final ModifyAction currentAction = dataTreeChangeTracker.popAction();
+
+ //if we know that we are going to delete a parent node just complete the entire subtree
+ if (dataTreeChangeTracker.getDeleteOperationTracker() > 0
+ || dataTreeChangeTracker.getRemoveOperationTracker() > 0) {
+ dataTreeChangeTracker.popPath();
+ } else {
+ //if parent and current actions don't match create a DataTreeChange and add it to the change list
+ //don't add a new child to the parent node
+ if (!currentAction.equals(dataTreeChangeTracker.peekAction())) {
+ dataTreeChangeTracker.addDataTreeChange(new DataTreeChangeTracker.DataTreeChange(product,
+ currentAction, new ArrayList<>(dataTreeChangeTracker.getCurrentPath())));
+ if (getCurrent() instanceof NormalizedNodeResultBuilder) {
+ dataTreeChangeTracker.popPath();
+ return;
+ }
+ getCurrent().removeChild(dataTreeChangeTracker.popPath());
+ } else {
+ dataTreeChangeTracker.popPath();
+ return;
+ }
+ }
+ }
+
+ // for (ordered) leaf-lists, (ordered) lists and unkeyed lists
+ if (finishedBuilder instanceof CollectionNodeBuilder) {
+ dataTreeChangeTracker.popPath();
+ }
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2015 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.netconf.mdsal.connector.ops;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Map;
-import javax.annotation.Nullable;
-import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.EditConfigInput;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.ModifyAction;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
-import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
-import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser.ExtensibleParser;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
-
-class EditOperationStrategyProvider extends DomToNormalizedNodeParserFactory.BuildingStrategyProvider {
-
- private static final QName OPERATION_ATTRIBUTE = QName.create(EditConfigInput.QNAME.getNamespace(), null,
- XmlNetconfConstants.OPERATION_ATTR_KEY);
-
- private final DataTreeChangeTracker changeTracker;
-
- EditOperationStrategyProvider(final DataTreeChangeTracker changeTracker) {
- this.changeTracker = changeTracker;
- }
-
- @Override
- protected ExtensibleParser.BuildingStrategy<NodeIdentifier, LeafNode<?>> forLeaf() {
- return new NetconfOperationLeafStrategy(changeTracker);
- }
-
- @Override
- protected ExtensibleParser.BuildingStrategy<NodeIdentifier, ContainerNode> forContainer() {
- return new NetconfOperationContainerStrategy<>(changeTracker);
- }
-
- @Override
- protected ExtensibleParser.BuildingStrategy<NodeIdentifier, MapNode> forMap() {
- return new NetconfOperationCollectionStrategy<>(changeTracker);
- }
-
- @Override
- protected ExtensibleParser.BuildingStrategy<NodeWithValue, LeafSetEntryNode<?>> forLeafSetEntry() {
- return new NetconfOperationLeafSetEntryStrategy(changeTracker);
- }
-
- @Override
- protected ExtensibleParser.BuildingStrategy<NodeIdentifierWithPredicates, MapEntryNode> forMapEntry() {
- return new NetconfOperationContainerStrategy<>(changeTracker);
- }
-
- @Override
- protected ExtensibleParser.BuildingStrategy<NodeIdentifier, OrderedMapNode> forOrderedList() {
- return new NetconfOperationCollectionStrategy<>(changeTracker);
- }
-
- @Override
- protected ExtensibleParser.BuildingStrategy<NodeIdentifier, UnkeyedListEntryNode> forUnkeyedListEntry() {
- return new NetconfOperationContainerStrategy<>(changeTracker);
- }
-
- @Override
- protected ExtensibleParser.BuildingStrategy<NodeIdentifier, UnkeyedListNode> forUnkeyedList() {
- return new NetconfOperationCollectionStrategy<>(changeTracker);
- }
-
- @Override
- protected ExtensibleParser.BuildingStrategy<NodeIdentifier, ChoiceNode> forChoice() {
- return new NetconfOperationContainerStrategy<>(changeTracker);
- }
-
- @Override
- public ExtensibleParser.BuildingStrategy<AugmentationIdentifier, AugmentationNode> forAugmentation() {
- return new NetconfOperationContainerStrategy<>(changeTracker);
- }
-
- private static class NetconfOperationCollectionStrategy<N extends NormalizedNode<NodeIdentifier, ?>>
- implements ExtensibleParser.BuildingStrategy<NodeIdentifier, N> {
- private final DataTreeChangeTracker changeTracker;
-
- NetconfOperationCollectionStrategy(final DataTreeChangeTracker changeTracker) {
- this.changeTracker = changeTracker;
- }
-
- @Nullable
- @Override
- public N build(final NormalizedNodeBuilder<NodeIdentifier, ?, N> builder) {
- changeTracker.popPath();
- return builder.build();
- }
-
- @Override
- public void prepareAttributes(
- final Map<QName, String> attributes,
- final NormalizedNodeBuilder<NodeIdentifier, ?, N> containerBuilder) {
- changeTracker.pushPath(containerBuilder.build().getIdentifier());
- }
- }
-
- public static final class NetconfOperationLeafStrategy
- implements ExtensibleParser.BuildingStrategy<NodeIdentifier, LeafNode<?>> {
-
- private final DataTreeChangeTracker dataTreeChangeTracker;
-
- NetconfOperationLeafStrategy(final DataTreeChangeTracker dataTreeChangeTracker) {
- this.dataTreeChangeTracker = dataTreeChangeTracker;
- }
-
- @Nullable
- @Override
- public LeafNode<?> build(
- final NormalizedNodeBuilder<NodeIdentifier, ?, LeafNode<?>> builder) {
- LeafNode<?> node = builder.build();
- String operation = (String) node.getAttributeValue(OPERATION_ATTRIBUTE);
- if (operation == null) {
- return node;
- }
-
- if (builder instanceof AttributesBuilder<?>) {
- ((AttributesBuilder<?>) builder).withAttributes(Collections.<QName, String>emptyMap());
- }
-
- node = builder.build();
-
- ModifyAction action = ModifyAction.fromXmlValue(operation);
- if (dataTreeChangeTracker.getDeleteOperationTracker() > 0
- || dataTreeChangeTracker .getRemoveOperationTracker() > 0) {
- return node;
- }
-
- if (action.equals(dataTreeChangeTracker.peekAction())) {
- return node;
- }
-
- dataTreeChangeTracker.pushPath(node.getIdentifier());
- dataTreeChangeTracker.addDataTreeChange(new DataTreeChangeTracker.DataTreeChange(node, action,
- new ArrayList<>(dataTreeChangeTracker.getCurrentPath())));
- dataTreeChangeTracker.popPath();
- return null;
- }
-
- @Override
- public void prepareAttributes(
- final Map<QName, String> attributes,
- final NormalizedNodeBuilder<NodeIdentifier, ?, LeafNode<?>> containerBuilder) {
- // Noop
- }
- }
-
- public static final class NetconfOperationLeafSetEntryStrategy
- implements ExtensibleParser.BuildingStrategy<NodeWithValue, LeafSetEntryNode<?>> {
-
- private final DataTreeChangeTracker dataTreeChangeTracker;
-
- NetconfOperationLeafSetEntryStrategy(final DataTreeChangeTracker dataTreeChangeTracker) {
- this.dataTreeChangeTracker = dataTreeChangeTracker;
- }
-
- @Nullable
- @Override
- public LeafSetEntryNode<?> build(final NormalizedNodeBuilder<NodeWithValue, ?, LeafSetEntryNode<?>> builder) {
- LeafSetEntryNode<?> node = builder.build();
- String operation = (String) node.getAttributeValue(OPERATION_ATTRIBUTE);
- if (operation == null) {
- return node;
- }
-
- if (builder instanceof AttributesBuilder<?>) {
- ((AttributesBuilder<?>) builder).withAttributes(Collections.<QName, String>emptyMap());
- }
-
- node = builder.build();
-
- ModifyAction action = ModifyAction.fromXmlValue(operation);
- if (dataTreeChangeTracker.getDeleteOperationTracker() > 0
- || dataTreeChangeTracker.getRemoveOperationTracker() > 0) {
- return node;
- }
-
- if (action.equals(dataTreeChangeTracker.peekAction())) {
- return node;
- }
-
- dataTreeChangeTracker.pushPath(node.getIdentifier());
- dataTreeChangeTracker.addDataTreeChange(new DataTreeChangeTracker.DataTreeChange(node, action,
- new ArrayList<>(dataTreeChangeTracker.getCurrentPath())));
- dataTreeChangeTracker.popPath();
- return null;
- }
-
- @Override
- public void prepareAttributes(
- final Map<QName, String> attributes,
- final NormalizedNodeBuilder<NodeWithValue, ?, LeafSetEntryNode<?>> containerBuilder) {
- }
- }
-
- public static final class NetconfOperationContainerStrategy<P extends PathArgument, N
- extends DataContainerNode<P>> implements ExtensibleParser.BuildingStrategy<P, N> {
-
- private final DataTreeChangeTracker dataTreeChangeTracker;
-
- NetconfOperationContainerStrategy(final DataTreeChangeTracker dataTreeChangeTracker) {
- this.dataTreeChangeTracker = dataTreeChangeTracker;
- }
-
- @Nullable
- @Override
- public N build(final NormalizedNodeBuilder<P, ?, N> builder) {
- if (builder instanceof AttributesBuilder<?>) {
- ((AttributesBuilder<?>) builder).withAttributes(Collections.<QName, String>emptyMap());
- }
-
- final N node = builder.build();
- final ModifyAction currentAction = dataTreeChangeTracker.popAction();
-
- //if we know that we are going to delete a parent node just complete the entire subtree
- if (dataTreeChangeTracker.getDeleteOperationTracker() > 0
- || dataTreeChangeTracker.getRemoveOperationTracker() > 0) {
- dataTreeChangeTracker.popPath();
- return node;
- }
-
- if (currentAction.equals(dataTreeChangeTracker.peekAction())) {
- dataTreeChangeTracker.popPath();
- return node;
- }
-
- //if parent and current actions dont match create a DataTreeChange and add it to the change list
- //dont add a new child to the parent node
- dataTreeChangeTracker.addDataTreeChange(new DataTreeChangeTracker.DataTreeChange(node,
- currentAction, new ArrayList<>(dataTreeChangeTracker.getCurrentPath())));
- dataTreeChangeTracker.popPath();
- return null;
- }
-
- @Override
- public void prepareAttributes(final Map<QName, String> attributes,
- final NormalizedNodeBuilder<P, ?, N> containerBuilder) {
- dataTreeChangeTracker.pushPath(containerBuilder.build().getIdentifier());
- final String operation = attributes.get(OPERATION_ATTRIBUTE);
- if (operation != null) {
- dataTreeChangeTracker.pushAction(ModifyAction.fromXmlValue(operation));
- } else {
- dataTreeChangeTracker.pushAction(dataTreeChangeTracker.peekAction() != null
- ? dataTreeChangeTracker.peekAction() : dataTreeChangeTracker.getDefaultAction());
- }
- }
- }
-}
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.CheckedFuture;
import java.io.IOException;
+import java.io.StringReader;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.netconf.api.NetconfDocumentedException;
import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.netconf.mapping.api.HandlingPriority;
import org.opendaylight.netconf.mapping.api.NetconfOperationChainedExecution;
import org.opendaylight.netconf.mdsal.connector.CurrentSchemaContext;
import org.opendaylight.netconf.util.mapping.AbstractSingletonNetconfOperation;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
import org.opendaylight.yangtools.yang.data.impl.schema.SchemaOrderedNormalizedNodeWriter;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
* @param input input container schema node, or null if rpc does not take any input
* @return parsed rpc into normalized node, or null if input schema is null
*/
+ @SuppressWarnings("checkstyle:IllegalCatch")
@Nullable
- private NormalizedNode<?, ?> rpcToNNode(final XmlElement element, @Nullable final ContainerSchemaNode input) {
- return input.getChildNodes().isEmpty() ? null : DomToNormalizedNodeParserFactory
- .getInstance(DomUtils.defaultValueCodecProvider(), schemaContext.getCurrentContext())
- .getContainerNodeParser()
- .parse(Collections.singletonList(element.getDomElement()), input);
+ private NormalizedNode<?, ?> rpcToNNode(final XmlElement element, @Nullable final ContainerSchemaNode input)
+ throws DocumentedException {
+ if (input.getChildNodes().isEmpty()) {
+ return null;
+ }
+
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, schemaContext.getCurrentContext(), input);
+
+ try {
+ xmlParser.parse(UntrustedXML.createXMLStreamReader(new StringReader(XmlUtil.toString(element))));
+ } catch (final Exception ex) {
+ throw new NetconfDocumentedException("Error parsing input: " + ex.getMessage(), ex, ErrorType.PROTOCOL,
+ ErrorTag.MALFORMED_MESSAGE, ErrorSeverity.ERROR);
+ }
+
+ return resultHolder.getResult();
}
}
--- /dev/null
+/*
+ * Copyright (c) 2017 Bell Canada. 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.netconf.api;
+
+/**
+ * FailedNetconfMessage represents a wrapper around NetconfMessage.
+ */
+public class FailedNetconfMessage extends NetconfMessage {
+
+ private Throwable exception;
+
+ public FailedNetconfMessage(final Throwable exception) {
+ this.exception = exception;
+ }
+
+ public Throwable getException() {
+ return this.exception;
+ }
+}
private final Document doc;
+ public NetconfMessage() {
+ // Required for FailedNetconfMessage
+ this.doc = null;
+ }
+
public NetconfMessage(final Document doc) {
this.doc = doc;
}
import java.io.IOException;
import java.util.List;
import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.netconf.api.FailedNetconfMessage;
import org.opendaylight.netconf.api.NetconfMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
public final class NetconfXMLToMessageDecoder extends ByteToMessageDecoder {
private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class);
}
}
if (in.isReadable()) {
- out.add(new NetconfMessage(XmlUtil.readXmlToDocument(new ByteBufInputStream(in))));
+ NetconfMessage msg;
+
+ try {
+ msg = new NetconfMessage(XmlUtil.readXmlToDocument(new ByteBufInputStream(in)));
+ } catch (SAXParseException exception) {
+ LOG.error("Failed to parse received message", exception);
+ msg = new FailedNetconfMessage(exception);
+ }
+
+ out.add(msg);
} else {
LOG.debug("No more content in incoming buffer.");
}
package org.opendaylight.netconf.nettyutil.handler;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import com.google.common.collect.Lists;
import io.netty.buffer.Unpooled;
import java.util.ArrayList;
import org.junit.Test;
+import org.opendaylight.netconf.api.FailedNetconfMessage;
import org.xml.sax.SAXParseException;
public class NetconfXMLToMessageDecoderTest {
assertEquals(1, out.size());
}
- @Test(expected = SAXParseException.class)
+ @Test
public void testDecodeGibberish() throws Exception {
/* Test that we reject inputs where we cannot find the xml start '<' character */
final ArrayList<Object> out = Lists.newArrayList();
new NetconfXMLToMessageDecoder().decode(null, Unpooled.wrappedBuffer("\r\n?xml version>".getBytes()), out);
assertEquals(1, out.size());
+ assertTrue(FailedNetconfMessage.class.isInstance(out.get(0)));
+ assertTrue(((FailedNetconfMessage) out.get(0))
+ .getException().getClass().isAssignableFrom(SAXParseException.class));
}
@Test
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.StringWriter;
+import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.concurrent.ExecutionException;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
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.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
-import org.xml.sax.SAXException;
/**
* Holds URLs with YANG schema resources for all yang modules reported in
? Optional.of(resultHolder.getResult()) : Optional.<NormalizedNode<?, ?>>absent();
}
+ @SuppressWarnings("checkstyle:IllegalCatch")
private static Optional<NormalizedNode<?, ?>> readXml(final InputStream in) {
- final DomToNormalizedNodeParserFactory parserFactory =
- DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, LIBRARY_CONTEXT);
try {
final DocumentBuilder docBuilder = UntrustedXML.newDocumentBuilder();
}
}
- final Transformer transformer = TransformerFactory.newInstance().newTransformer();
- final StringWriter sw = new StringWriter();
- transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
- transformer.transform(new DOMSource(doc), new StreamResult(sw));
- final NormalizedNode<?, ?> parsed =
- parserFactory.getContainerNodeParser()
- .parse(Collections.singleton(XmlUtil.readXmlToElement(sw.toString())),
- (ContainerSchemaNode) LIBRARY_CONTEXT.getDataChildByName(ModulesState.QNAME));
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, LIBRARY_CONTEXT,
+ LIBRARY_CONTEXT.getDataChildByName(ModulesState.QNAME));
+
+ xmlParser.parse(UntrustedXML.createXMLStreamReader(new StringReader(XmlUtil.toString(
+ doc.getDocumentElement(), false))));
+ final NormalizedNode<?, ?> parsed = resultHolder.getResult();
return Optional.of(parsed);
- } catch (final SAXException | IOException | TransformerException e) {
+ } catch (final Exception e) {
LOG.warn("Unable to parse yang library xml content", e);
}
import java.util.concurrent.locks.ReentrantLock;
import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.netconf.api.FailedNetconfMessage;
import org.opendaylight.netconf.api.NetconfDocumentedException;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.NetconfTerminationReason;
if (request != null) {
+ if (FailedNetconfMessage.class.isInstance(message)) {
+ request.future.set(NetconfMessageTransformUtil.toRpcResult((FailedNetconfMessage) message));
+ return;
+ }
+
LOG.debug("{}: Message received {}", id, message);
if (LOG.isTraceEnabled()) {
}
private static boolean isNotification(final NetconfMessage message) {
+ if (message.getDocument() == null) {
+ // We have no message, which mean we have a FailedNetconfMessage
+ return false;
+ }
final XmlElement xmle = XmlElement.fromDomDocument(message.getDocument());
return XmlNetconfConstants.NOTIFICATION_ELEMENT_NAME.equals(xmle.getName()) ;
}
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import java.io.IOException;
+import java.io.StringReader;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import javax.xml.transform.dom.DOMResult;
import org.opendaylight.controller.config.util.xml.MissingNameSpaceException;
import org.opendaylight.controller.config.util.xml.XmlElement;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.md.sal.dom.api.DOMEvent;
import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.MessageCounter;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+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.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
private final MessageCounter counter;
private final Map<QName, RpcDefinition> mappedRpcs;
private final Multimap<QName, NotificationDefinition> mappedNotifications;
- private final DomToNormalizedNodeParserFactory parserFactory;
+
+ private final boolean strictParsing;
public NetconfMessageTransformer(final SchemaContext schemaContext, final boolean strictParsing) {
this(schemaContext, strictParsing, BaseSchema.BASE_NETCONF_CTX);
final BaseSchema baseSchema) {
this.counter = new MessageCounter();
this.schemaContext = schemaContext;
- parserFactory = DomToNormalizedNodeParserFactory
- .getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, schemaContext, strictParsing);
mappedRpcs = Maps.uniqueIndex(schemaContext.getOperations(), SchemaNode::getQName);
mappedNotifications = Multimaps.index(schemaContext.getNotifications(),
node -> node.getQName().withoutRevision());
this.baseSchema = baseSchema;
+ this.strictParsing = strictParsing;
}
+ @SuppressWarnings("checkstyle:IllegalCatch")
@Override
public synchronized DOMNotification toNotification(final NetconfMessage message) {
final Map.Entry<Date, XmlElement> stripped = NetconfMessageTransformUtil.stripNotification(message);
final Element element = stripped.getValue().getDomElement();
final ContainerNode content;
try {
- content = parserFactory.getContainerNodeParser().parse(Collections.singleton(element),
- notificationAsContainerSchemaNode);
- } catch (IllegalArgumentException e) {
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, schemaContext,
+ notificationAsContainerSchemaNode, strictParsing);
+
+ xmlParser.parse(UntrustedXML.createXMLStreamReader(new StringReader(XmlUtil.toString(element))));
+ content = (ContainerNode) resultHolder.getResult();
+ } catch (final Exception e) {
throw new IllegalArgumentException(String.format("Failed to parse notification %s", element), e);
}
return new NetconfDeviceNotification(content, stripped.getKey());
|| rpc.getNamespace().equals(NetconfMessageTransformUtil.CREATE_SUBSCRIPTION_RPC_QNAME.getNamespace());
}
-
+ @SuppressWarnings("checkstyle:IllegalCatch")
@Override
public synchronized DOMRpcResult toRpcResult(final NetconfMessage message, final SchemaPath rpc) {
final NormalizedNode<?, ?> normalizedNode;
final ContainerNode dataNode;
try {
- dataNode =
- parserFactory.getContainerNodeParser().parse(Collections.singleton(xmlData), schemaForDataRead);
- } catch (IllegalArgumentException e) {
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, schemaContext, schemaForDataRead,
+ strictParsing);
+
+ xmlParser.parse(UntrustedXML.createXMLStreamReader(new StringReader(XmlUtil.toString(xmlData))));
+ dataNode = (ContainerNode) resultHolder.getResult();
+ } catch (final Exception e) {
throw new IllegalArgumentException(String.format("Failed to parse data response %s", xmlData), e);
}
} else {
final Element element = message.getDocument().getDocumentElement();
try {
- normalizedNode = parserFactory.getContainerNodeParser().parse(Collections.singleton(element),
- rpcDefinition.getOutput());
- } catch (IllegalArgumentException e) {
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, schemaContext,
+ rpcDefinition.getOutput(), strictParsing);
+
+ xmlParser.parse(UntrustedXML.createXMLStreamReader(new StringReader(XmlUtil.toString(element))));
+ normalizedNode = resultHolder.getResult();
+ } catch (final Exception e) {
throw new IllegalArgumentException(String.format("Failed to parse RPC response %s", element), e);
}
}
import org.opendaylight.controller.config.util.xml.DocumentedException;
import org.opendaylight.controller.config.util.xml.XmlElement;
import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.netconf.api.FailedNetconfMessage;
import org.opendaylight.netconf.api.NetconfDocumentedException;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.notifications.NetconfNotification;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
+import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.opendaylight.yangtools.yang.data.api.ModifyAction;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
}
}
}
+
+ public static RpcResult<NetconfMessage> toRpcResult(final FailedNetconfMessage message) {
+ return RpcResultBuilder.<NetconfMessage>failed()
+ .withRpcError(
+ toRpcError(
+ new NetconfDocumentedException(
+ message.getException().getMessage(),
+ DocumentedException.ErrorType.APPLICATION,
+ DocumentedException.ErrorTag.MALFORMED_MESSAGE,
+ DocumentedException.ErrorSeverity.ERROR)))
+ .build();
+ }
}
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.NetconfState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.Schemas;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+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.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
public class NetconfStateSchemasTest {
final DataSchemaNode schemasNode =
((ContainerSchemaNode) schemaContext
.getDataChildByName(NetconfState.QNAME)).getDataChildByName(Schemas.QNAME);
- final Document schemasXml =
- XmlUtil.readXmlToDocument(getClass().getResourceAsStream("/netconf-state.schemas.payload.xml"));
- final ToNormalizedNodeParser<Element, ContainerNode, ContainerSchemaNode> containerNodeParser =
- DomToNormalizedNodeParserFactory
- .getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, schemaContext, false).getContainerNodeParser();
- compositeNodeSchemas = containerNodeParser
- .parse(Collections.singleton(schemasXml.getDocumentElement()), (ContainerSchemaNode) schemasNode);
+
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, schemaContext, schemasNode, false);
+
+ xmlParser.parse(UntrustedXML.createXMLStreamReader(getClass().getResourceAsStream(
+ "/netconf-state.schemas.payload.xml")));
+ compositeNodeSchemas = (ContainerNode) resultHolder.getResult();
}
return context;
}
- @Test(expected = IllegalStateException.class)
+ @Test(expected = IllegalArgumentException.class)
public void testMostRecentWrongYangModel() throws Exception {
final SchemaContext schemaContext = getNotificationSchemaContext(getClass(), true);
messageTransformer = new NetconfMessageTransformer(schemaContext, true);
import com.google.common.base.Optional;
import java.io.IOException;
+import java.io.StringReader;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
-import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.netconf.cli.io.BaseConsoleContext;
import org.opendaylight.netconf.cli.io.ConsoleContext;
import org.opendaylight.netconf.cli.io.ConsoleIO;
import org.opendaylight.netconf.cli.reader.AbstractReader;
import org.opendaylight.netconf.cli.reader.ReadingException;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.DomUtils;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
public class AnyXmlReader extends AbstractReader<AnyXmlSchemaNode> {
return newNodes;
}
+ @SuppressWarnings("checkstyle:IllegalCatch")
private Optional<DataContainerChild<?, ?>> tryParse(final String rawValue, final AnyXmlSchemaNode schemaNode) {
try {
- final Document dom = XmlUtil.readXmlToDocument(rawValue);
- return Optional.of(
- DomToNormalizedNodeParserFactory
- .getInstance(DomUtils.defaultValueCodecProvider(), getSchemaContext())
- .getAnyXmlNodeParser()
- .parse(Collections.singletonList(dom.getDocumentElement()), schemaNode)
- );
- } catch (SAXException | IOException e) {
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, getSchemaContext(), schemaNode);
+
+ xmlParser.parse(UntrustedXML.createXMLStreamReader(new StringReader(rawValue)));
+ return Optional.of((DataContainerChild<?, ?>) resultHolder.getResult());
+ } catch (final Exception e) {
// TODO log
return Optional.absent();
}
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-config</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-util</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
import com.google.common.collect.Iterables;
import java.io.IOException;
import java.io.InputStream;
+import java.io.StringReader;
+import java.net.URISyntaxException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.Deque;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
@Provider
@Consumes({ Rfc8040.MediaTypes.DATA + RestconfConstants.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
}
}
- private NormalizedNodeContext parse(final InstanceIdentifierContext<?> pathContext,final Document doc) {
-
- final List<Element> elements = Collections.singletonList(doc.getDocumentElement());
+ private NormalizedNodeContext parse(final InstanceIdentifierContext<?> pathContext, final Document doc)
+ throws XMLStreamException, IOException, ParserConfigurationException, SAXException, URISyntaxException {
final SchemaNode schemaNodeContext = pathContext.getSchemaNode();
DataSchemaNode schemaNode;
boolean isRpc = false;
final String docRootElm = doc.getDocumentElement().getLocalName();
final String docRootNamespace = doc.getDocumentElement().getNamespaceURI();
final List<YangInstanceIdentifier.PathArgument> iiToDataList = new ArrayList<>();
- InstanceIdentifierContext<? extends SchemaNode> outIIContext;
-
- final DomToNormalizedNodeParserFactory parserFactory =
- DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER,
- pathContext.getSchemaContext());
if (isPost() && !isRpc) {
final Deque<Object> foundSchemaNodes = findPathToSchemaNodeByName(schemaNode, docRootElm, docRootNamespace);
docRootElm, scQName));
}
- final NormalizedNode<?, ?> parsed;
- if (schemaNode instanceof ContainerSchemaNode) {
- parsed = parserFactory.getContainerNodeParser().parse(
- Collections.singletonList(doc.getDocumentElement()), (ContainerSchemaNode) schemaNode);
- } else if (schemaNode instanceof ListSchemaNode) {
- parsed = parserFactory.getMapEntryNodeParser().parse(elements, (ListSchemaNode) schemaNode);
- if (isPost()) {
+ NormalizedNode<?, ?> parsed = null;
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+
+ if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode
+ || schemaNode instanceof LeafSchemaNode) {
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, pathContext.getSchemaContext(),
+ schemaNode);
+ xmlParser.parse(UntrustedXML.createXMLStreamReader(new StringReader(XmlUtil.toString(
+ doc.getDocumentElement()))));
+ parsed = resultHolder.getResult();
+ if (schemaNode instanceof ListSchemaNode && isPost()) {
iiToDataList.add(parsed.getIdentifier());
}
- } else if (schemaNode instanceof LeafSchemaNode) {
- parsed = parserFactory.getLeafNodeParser().parse(elements, (LeafSchemaNode) schemaNode);
- } else {
- LOG.warn("Unknown schema node extension {} was not parsed", schemaNode.getClass());
- parsed = null;
}
+ LOG.warn("Unknown schema node extension {} was not parsed", schemaNode.getClass());
+
final YangInstanceIdentifier fullIIToData = YangInstanceIdentifier.create(Iterables.concat(
pathContext.getInstanceIdentifier().getPathArguments(), iiToDataList));
- outIIContext = new InstanceIdentifierContext<>(fullIIToData, pathContext.getSchemaNode(),
- pathContext.getMountPoint(),
- pathContext.getSchemaContext());
+ final InstanceIdentifierContext<? extends SchemaNode> outIIContext = new InstanceIdentifierContext<>(
+ fullIIToData, pathContext.getSchemaNode(), pathContext.getMountPoint(), pathContext.getSchemaContext());
return new NormalizedNodeContext(outIIContext, parsed);
}
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.InputStream;
+import java.io.StringReader;
import java.net.URI;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.Provider;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
import org.opendaylight.netconf.sal.restconf.impl.PatchContext;
import org.opendaylight.netconf.sal.restconf.impl.PatchEditOperation;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
+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.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
@Provider
@Consumes({Rfc8040.MediaTypes.PATCH + RestconfConstants.XML})
}
}
- private static PatchContext parse(final InstanceIdentifierContext<?> pathContext, final Document doc) {
+ private static PatchContext parse(final InstanceIdentifierContext<?> pathContext, final Document doc)
+ throws XMLStreamException, IOException, ParserConfigurationException, SAXException, URISyntaxException {
final List<PatchEntity> resultCollection = new ArrayList<>();
final String patchId = doc.getElementsByTagName("patch-id").item(0).getFirstChild().getNodeValue();
final NodeList editNodes = doc.getElementsByTagName("edit");
- final DomToNormalizedNodeParserFactory parserFactory =
- DomToNormalizedNodeParserFactory.getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER,
- pathContext.getSchemaContext());
for (int i = 0; i < editNodes.getLength(); i++) {
DataSchemaNode schemaNode = (DataSchemaNode) pathContext.getSchemaNode();
}
if (oper.isWithValue()) {
- final NormalizedNode<?, ?> parsed;
- if (schemaNode instanceof ContainerSchemaNode) {
- parsed = parserFactory.getContainerNodeParser().parse(values, (ContainerSchemaNode) schemaNode);
- } else if (schemaNode instanceof ListSchemaNode) {
- parsed = parserFactory.getMapNodeParser().parse(values, (ListSchemaNode) schemaNode);
- } else {
- parsed = null;
+ NormalizedNode<?, ?> parsed = null;
+ if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode) {
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, pathContext.getSchemaContext(),
+ schemaNode);
+ xmlParser.parse(UntrustedXML.createXMLStreamReader(new StringReader(XmlUtil.toString(
+ firstValueElement))));
+ parsed = resultHolder.getResult();
}
// for lists allow to manipulate with list items through their parent
import com.google.common.base.Preconditions;
import java.io.File;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.io.InputStream;
+import java.io.StringReader;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.sal.rest.impl.test.providers.TestJsonBodyWriter;
import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
import org.opendaylight.yangtools.util.xml.UntrustedXML;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlUtils;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.dom.parser.DomToNormalizedNodeParserFactory;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
+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.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
public class TestRestconfUtils {
return null;
}
- private static NormalizedNode<?, ?> parse(final InstanceIdentifierContext<?> iiContext, final Document doc) {
- final List<Element> elements = Collections.singletonList(doc.getDocumentElement());
+ private static NormalizedNode<?, ?> parse(final InstanceIdentifierContext<?> iiContext, final Document doc)
+ throws XMLStreamException, IOException, ParserConfigurationException, SAXException, URISyntaxException {
final SchemaNode schemaNodeContext = iiContext.getSchemaNode();
DataSchemaNode schemaNode = null;
if (schemaNodeContext instanceof RpcDefinition) {
}
}
}
- final DomToNormalizedNodeParserFactory parserFactory = DomToNormalizedNodeParserFactory
- .getInstance(XmlUtils.DEFAULT_XML_CODEC_PROVIDER, iiContext.getSchemaContext());
- if (schemaNode instanceof ContainerSchemaNode) {
- return parserFactory.getContainerNodeParser().parse(Collections.singletonList(doc.getDocumentElement()),
- (ContainerSchemaNode) schemaNode);
- } else if (schemaNode instanceof ListSchemaNode) {
- final ListSchemaNode casted = (ListSchemaNode) schemaNode;
- return parserFactory.getMapEntryNodeParser().parse(elements, casted);
- } // FIXME : add another DataSchemaNode extensions e.g. LeafSchemaNode
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, iiContext.getSchemaContext(), schemaNode);
+
+ if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode) {
+ xmlParser.parse(UntrustedXML.createXMLStreamReader(new StringReader(XmlUtil.toString(
+ doc.getDocumentElement()))));
+ return resultHolder.getResult();
+ }
+ // FIXME : add another DataSchemaNode extensions e.g. LeafSchemaNode
return null;
}
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import com.google.common.util.concurrent.UncheckedExecutionException;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.regex.Matcher;
validateJson(".*\"lf2\":\\p{Blank}*\"121\".*", json);
}
- @Test(expected = UncheckedExecutionException.class)
+ @Test(expected = NullPointerException.class)
public void leafrefToNonExistingLeafTest() throws Exception {
toJson("/nn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml");
}