* 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.restconf.nb.rfc8040.jersey.providers;
+import static java.util.Objects.requireNonNull;
import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
import com.google.common.annotations.Beta;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
-import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
import java.util.Set;
+import javax.xml.transform.dom.DOMSource;
+import org.opendaylight.restconf.nb.rfc8040.DepthParam;
import org.opendaylight.restconf.nb.rfc8040.jersey.providers.api.RestconfNormalizedNodeWriter;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.AnydataNode;
+import org.opendaylight.yangtools.yang.data.api.schema.AnyxmlNode;
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.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.OrderedLeafSetNode;
-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.api.schema.stream.NormalizedNodeStreamAttributeWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.UserLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UserMapNode;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
protected final List<Set<QName>> fields;
protected int currentDepth = 0;
- private ParameterAwareNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final Integer maxDepth,
+ private ParameterAwareNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final DepthParam depth,
final List<Set<QName>> fields) {
- this.writer = Preconditions.checkNotNull(writer);
- this.maxDepth = maxDepth;
+ this.writer = requireNonNull(writer);
+ maxDepth = depth == null ? null : depth.value();
this.fields = fields;
}
* @return A new instance.
*/
public static ParameterAwareNormalizedNodeWriter forStreamWriter(
- final NormalizedNodeStreamWriter writer, final Integer maxDepth, final List<Set<QName>> fields) {
+ final NormalizedNodeStreamWriter writer, final DepthParam maxDepth, final List<Set<QName>> fields) {
return forStreamWriter(writer, true, maxDepth, fields);
}
/**
* Create a new writer backed by a {@link NormalizedNodeStreamWriter}. Unlike the simple
- * {@link #forStreamWriter(NormalizedNodeStreamWriter, Integer, List)}
- * method, this allows the caller to switch off RFC6020 XML compliance, providing better
- * throughput. The reason is that the XML mapping rules in RFC6020 require the encoding
- * to emit leaf nodes which participate in a list's key first and in the order in which
- * they are defined in the key. For JSON, this requirement is completely relaxed and leaves
- * can be ordered in any way we see fit. The former requires a bit of work: first a lookup
- * for each key and then for each emitted node we need to check whether it was already
- * emitted.
+ * {@link #forStreamWriter(NormalizedNodeStreamWriter, DepthParam, List)} method, this allows the caller to
+ * switch off RFC6020 XML compliance, providing better throughput. The reason is that the XML mapping rules in
+ * RFC6020 require the encoding to emit leaf nodes which participate in a list's key first and in the order in which
+ * they are defined in the key. For JSON, this requirement is completely relaxed and leaves can be ordered in any
+ * way we see fit. The former requires a bit of work: first a lookup for each key and then for each emitted node we
+ * need to check whether it was already emitted.
*
* @param writer Back-end writer
* @param orderKeyLeaves whether the returned instance should be RFC6020 XML compliant.
- * @param maxDepth Maximal depth to write
+ * @param depth Maximal depth to write
* @param fields Selected child nodes to write
* @return A new instance.
*/
public static ParameterAwareNormalizedNodeWriter forStreamWriter(final NormalizedNodeStreamWriter writer,
final boolean orderKeyLeaves,
- final Integer maxDepth,
+ final DepthParam depth,
final List<Set<QName>> fields) {
- return orderKeyLeaves ? new OrderedParameterAwareNormalizedNodeWriter(writer, maxDepth, fields)
- : new ParameterAwareNormalizedNodeWriter(writer, maxDepth, fields);
+ return orderKeyLeaves ? new OrderedParameterAwareNormalizedNodeWriter(writer, depth, fields)
+ : new ParameterAwareNormalizedNodeWriter(writer, depth, fields);
}
/**
* @throws IOException when thrown from the backing writer.
*/
@Override
- public final ParameterAwareNormalizedNodeWriter write(final NormalizedNode<?, ?> node) throws IOException {
+ public final ParameterAwareNormalizedNodeWriter write(final NormalizedNode node) throws IOException {
if (wasProcessedAsCompositeNode(node)) {
return this;
}
return children instanceof Collection ? ((Collection<?>) children).size() : UNKNOWN_SIZE;
}
- private boolean wasProcessAsSimpleNode(final NormalizedNode<?, ?> node) throws IOException {
+ private boolean wasProcessAsSimpleNode(final NormalizedNode node) throws IOException {
if (node instanceof LeafSetEntryNode) {
if (selectedByParameters(node, false)) {
final LeafSetEntryNode<?> nodeAsLeafList = (LeafSetEntryNode<?>) node;
- if (writer instanceof NormalizedNodeStreamAttributeWriter) {
- ((NormalizedNodeStreamAttributeWriter) writer).leafSetEntryNode(nodeAsLeafList.getNodeType(),
- nodeAsLeafList.getValue(), nodeAsLeafList.getAttributes());
- } else {
- writer.leafSetEntryNode(nodeAsLeafList.getNodeType(), nodeAsLeafList.getValue());
- }
+ writer.startLeafSetEntryNode(nodeAsLeafList.getIdentifier());
+ writer.scalarValue(nodeAsLeafList.body());
+ writer.endNode();
}
return true;
} else if (node instanceof LeafNode) {
final LeafNode<?> nodeAsLeaf = (LeafNode<?>)node;
- if (writer instanceof NormalizedNodeStreamAttributeWriter) {
- ((NormalizedNodeStreamAttributeWriter) writer).leafNode(
- nodeAsLeaf.getIdentifier(), nodeAsLeaf.getValue(), nodeAsLeaf.getAttributes());
- } else {
- writer.leafNode(nodeAsLeaf.getIdentifier(), nodeAsLeaf.getValue());
- }
- return true;
- } else if (node instanceof AnyXmlNode) {
- final AnyXmlNode anyXmlNode = (AnyXmlNode)node;
- writer.anyxmlNode(anyXmlNode.getIdentifier(), anyXmlNode.getValue());
+ writer.startLeafNode(nodeAsLeaf.getIdentifier());
+ writer.scalarValue(nodeAsLeaf.body());
+ writer.endNode();
return true;
+ } else if (node instanceof AnyxmlNode) {
+ final AnyxmlNode<?> anyxmlNode = (AnyxmlNode<?>)node;
+ final Class<?> objectModel = anyxmlNode.bodyObjectModel();
+ if (writer.startAnyxmlNode(anyxmlNode.getIdentifier(), objectModel)) {
+ if (DOMSource.class.isAssignableFrom(objectModel)) {
+ writer.domSourceValue((DOMSource) anyxmlNode.body());
+ } else {
+ writer.scalarValue(anyxmlNode.body());
+ }
+ writer.endNode();
+ return true;
+ }
+ } else if (node instanceof AnydataNode) {
+ final AnydataNode<?> anydataNode = (AnydataNode<?>)node;
+ final Class<?> objectModel = anydataNode.bodyObjectModel();
+ if (writer.startAnydataNode(anydataNode.getIdentifier(), objectModel)) {
+ writer.scalarValue(anydataNode.body());
+ writer.endNode();
+ return true;
+ }
}
return false;
* @param mixinParent {@code true} if parent is mixin, {@code false} otherwise
* @return {@code true} if node will be written, {@code false} otherwise
*/
- protected boolean selectedByParameters(final NormalizedNode<?, ?> node, final boolean mixinParent) {
+ protected boolean selectedByParameters(final NormalizedNode node, final boolean mixinParent) {
// nodes to be written are not limited by fields, only by depth
if (fields == null) {
return maxDepth == null || currentDepth < maxDepth;
// write only selected nodes
if (currentDepth > 0 && currentDepth <= fields.size()) {
- return fields.get(currentDepth - 1).contains(node.getNodeType());
+ return fields.get(currentDepth - 1).contains(node.getIdentifier().getNodeType());
}
// after this depth only depth parameter is used to determine when to write node
* @return True
* @throws IOException when the writer reports it
*/
- protected final boolean writeChildren(final Iterable<? extends NormalizedNode<?, ?>> children,
+ protected final boolean writeChildren(final Iterable<? extends NormalizedNode> children,
final boolean mixinParent) throws IOException {
- for (final NormalizedNode<?, ?> child : children) {
+ for (final NormalizedNode child : children) {
if (selectedByParameters(child, mixinParent)) {
write(child);
}
protected boolean writeMapEntryChildren(final MapEntryNode mapEntryNode) throws IOException {
if (selectedByParameters(mapEntryNode, false)) {
- writeChildren(mapEntryNode.getValue(), false);
+ writeChildren(mapEntryNode.body(), false);
} else if (fields == null && maxDepth != null && currentDepth == maxDepth) {
- writeOnlyKeys(mapEntryNode.getIdentifier().getKeyValues());
+ writeOnlyKeys(mapEntryNode.getIdentifier().entrySet());
}
return true;
}
- private void writeOnlyKeys(final Map<QName, Object> keyValues) throws IllegalArgumentException, IOException {
- for (final Map.Entry<QName, Object> entry : keyValues.entrySet()) {
- writer.leafNode(new NodeIdentifier(entry.getKey()), entry.getValue());
+ private void writeOnlyKeys(final Set<Entry<QName, Object>> entries) throws IOException {
+ for (final Entry<QName, Object> entry : entries) {
+ writer.startLeafNode(new NodeIdentifier(entry.getKey()));
+ writer.scalarValue(entry.getValue());
+ writer.endNode();
}
writer.endNode();
}
protected boolean writeMapEntryNode(final MapEntryNode node) throws IOException {
- if (writer instanceof NormalizedNodeStreamAttributeWriter) {
- ((NormalizedNodeStreamAttributeWriter) writer)
- .startMapEntryNode(node.getIdentifier(), childSizeHint(node.getValue()), node.getAttributes());
- } else {
- writer.startMapEntryNode(node.getIdentifier(), childSizeHint(node.getValue()));
- }
+ writer.startMapEntryNode(node.getIdentifier(), childSizeHint(node.body()));
currentDepth++;
writeMapEntryChildren(node);
currentDepth--;
return true;
}
- private boolean wasProcessedAsCompositeNode(final NormalizedNode<?, ?> node) throws IOException {
+ private boolean wasProcessedAsCompositeNode(final NormalizedNode node) throws IOException {
boolean processedAsCompositeNode = false;
if (node instanceof ContainerNode) {
final ContainerNode n = (ContainerNode) node;
- if (!n.getNodeType().equals(ROOT_DATA_QNAME)) {
- if (writer instanceof NormalizedNodeStreamAttributeWriter) {
- ((NormalizedNodeStreamAttributeWriter) writer).startContainerNode(
- n.getIdentifier(), childSizeHint(n.getValue()), n.getAttributes());
- } else {
- writer.startContainerNode(n.getIdentifier(), childSizeHint(n.getValue()));
- }
+ if (!n.getIdentifier().getNodeType().withoutRevision().equals(ROOT_DATA_QNAME)) {
+ writer.startContainerNode(n.getIdentifier(), childSizeHint(n.body()));
currentDepth++;
- processedAsCompositeNode = writeChildren(n.getValue(), false);
+ processedAsCompositeNode = writeChildren(n.body(), false);
currentDepth--;
} else {
// write child nodes of data root container
- for (final NormalizedNode<?, ?> child : n.getValue()) {
+ for (final NormalizedNode child : n.body()) {
currentDepth++;
if (selectedByParameters(child, false)) {
write(child);
}
currentDepth--;
- processedAsCompositeNode = true;
}
+ processedAsCompositeNode = true;
}
} else if (node instanceof MapEntryNode) {
processedAsCompositeNode = writeMapEntryNode((MapEntryNode) node);
} else if (node instanceof UnkeyedListEntryNode) {
final UnkeyedListEntryNode n = (UnkeyedListEntryNode) node;
- writer.startUnkeyedListItem(n.getIdentifier(), childSizeHint(n.getValue()));
+ writer.startUnkeyedListItem(n.getIdentifier(), childSizeHint(n.body()));
currentDepth++;
- processedAsCompositeNode = writeChildren(n.getValue(), false);
+ processedAsCompositeNode = writeChildren(n.body(), false);
currentDepth--;
} else if (node instanceof ChoiceNode) {
final ChoiceNode n = (ChoiceNode) node;
- writer.startChoiceNode(n.getIdentifier(), childSizeHint(n.getValue()));
- processedAsCompositeNode = writeChildren(n.getValue(), true);
+ writer.startChoiceNode(n.getIdentifier(), childSizeHint(n.body()));
+ processedAsCompositeNode = writeChildren(n.body(), true);
} else if (node instanceof AugmentationNode) {
final AugmentationNode n = (AugmentationNode) node;
writer.startAugmentationNode(n.getIdentifier());
- processedAsCompositeNode = writeChildren(n.getValue(), true);
+ processedAsCompositeNode = writeChildren(n.body(), true);
} else if (node instanceof UnkeyedListNode) {
final UnkeyedListNode n = (UnkeyedListNode) node;
- writer.startUnkeyedList(n.getIdentifier(), childSizeHint(n.getValue()));
- processedAsCompositeNode = writeChildren(n.getValue(), false);
- } else if (node instanceof OrderedMapNode) {
- final OrderedMapNode n = (OrderedMapNode) node;
- writer.startOrderedMapNode(n.getIdentifier(), childSizeHint(n.getValue()));
- processedAsCompositeNode = writeChildren(n.getValue(), true);
+ writer.startUnkeyedList(n.getIdentifier(), childSizeHint(n.body()));
+ processedAsCompositeNode = writeChildren(n.body(), false);
+ } else if (node instanceof UserMapNode) {
+ final UserMapNode n = (UserMapNode) node;
+ writer.startOrderedMapNode(n.getIdentifier(), childSizeHint(n.body()));
+ processedAsCompositeNode = writeChildren(n.body(), true);
} else if (node instanceof MapNode) {
final MapNode n = (MapNode) node;
- writer.startMapNode(n.getIdentifier(), childSizeHint(n.getValue()));
- processedAsCompositeNode = writeChildren(n.getValue(), true);
+ writer.startMapNode(n.getIdentifier(), childSizeHint(n.body()));
+ processedAsCompositeNode = writeChildren(n.body(), true);
} else if (node instanceof LeafSetNode) {
final LeafSetNode<?> n = (LeafSetNode<?>) node;
- if (node instanceof OrderedLeafSetNode) {
- writer.startOrderedLeafSet(n.getIdentifier(), childSizeHint(n.getValue()));
+ if (node instanceof UserLeafSetNode) {
+ writer.startOrderedLeafSet(n.getIdentifier(), childSizeHint(n.body()));
} else {
- writer.startLeafSet(n.getIdentifier(), childSizeHint(n.getValue()));
+ writer.startLeafSet(n.getIdentifier(), childSizeHint(n.body()));
}
currentDepth++;
- processedAsCompositeNode = writeChildren(n.getValue(), true);
+ processedAsCompositeNode = writeChildren(n.body(), true);
currentDepth--;
}
private static final class OrderedParameterAwareNormalizedNodeWriter extends ParameterAwareNormalizedNodeWriter {
private static final Logger LOG = LoggerFactory.getLogger(OrderedParameterAwareNormalizedNodeWriter.class);
- OrderedParameterAwareNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final Integer maxDepth,
+ OrderedParameterAwareNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final DepthParam depth,
final List<Set<QName>> fields) {
- super(writer, maxDepth, fields);
+ super(writer, depth, fields);
}
@Override
protected boolean writeMapEntryNode(final MapEntryNode node) throws IOException {
final NormalizedNodeStreamWriter writer = getWriter();
- if (writer instanceof NormalizedNodeStreamAttributeWriter) {
- ((NormalizedNodeStreamAttributeWriter) writer).startMapEntryNode(
- node.getIdentifier(), childSizeHint(node.getValue()), node.getAttributes());
- } else {
- writer.startMapEntryNode(node.getIdentifier(), childSizeHint(node.getValue()));
- }
+ writer.startMapEntryNode(node.getIdentifier(), childSizeHint(node.body()));
- final Set<QName> qnames = node.getIdentifier().getKeyValues().keySet();
+ final Set<QName> qnames = node.getIdentifier().keySet();
// Write out all the key children
currentDepth++;
for (final QName qname : qnames) {
- final Optional<? extends NormalizedNode<?, ?>> child = node.getChild(new NodeIdentifier(qname));
+ final Optional<? extends NormalizedNode> child = node.findChildByArg(new NodeIdentifier(qname));
if (child.isPresent()) {
if (selectedByParameters(child.get(), false)) {
write(child.get());
currentDepth++;
// Write all the rest
final boolean result =
- writeChildren(Iterables.filter(node.getValue(), input -> {
+ writeChildren(Iterables.filter(node.body(), input -> {
if (input instanceof AugmentationNode) {
return true;
}
- if (!qnames.contains(input.getNodeType())) {
+ if (!qnames.contains(input.getIdentifier().getNodeType())) {
return true;
}