2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.data.impl.schema;
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ArrayListMultimap;
12 import java.io.IOException;
13 import java.util.Collection;
14 import java.util.List;
15 import java.util.Objects;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
18 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
19 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
21 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
22 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
25 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
28 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 * This is an iterator over a {@link NormalizedNode}. Unlike {@link NormalizedNodeWriter}, this iterates over elements
35 * in the order as they are defined in YANG file.
37 public class SchemaOrderedNormalizedNodeWriter extends NormalizedNodeWriter {
38 private static final Logger LOG = LoggerFactory.getLogger(SchemaOrderedNormalizedNodeWriter.class);
39 private final SchemaContext schemaContext;
40 private final SchemaNode root;
42 private SchemaNode currentSchemaNode;
45 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
49 * @param schemaContext
54 public SchemaOrderedNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final SchemaContext schemaContext,
55 final SchemaPath path) {
57 this.schemaContext = schemaContext;
58 final Collection<SchemaNode> schemaNodes = SchemaUtils.findParentSchemaNodesOnPath(schemaContext, path);
59 Preconditions.checkArgument(!schemaNodes.isEmpty(), "Unable to find schema node for supplied schema path: %s",
61 if (schemaNodes.size() > 1) {
62 LOG.warn("More possible schema nodes {} for supplied schema path {}", schemaNodes, path);
64 this.root = schemaNodes.iterator().next();
68 public SchemaOrderedNormalizedNodeWriter write(final NormalizedNode<?, ?> node) throws IOException {
69 if (Objects.equals(root, schemaContext)) {
70 currentSchemaNode = schemaContext.getDataChildByName(node.getNodeType());
72 currentSchemaNode = root;
74 return write(node, currentSchemaNode);
78 * Iterate over the provided collection and emit write
79 * events to the encapsulated {@link NormalizedNodeStreamWriter}.
82 * @return NormalizedNodeWriter this
83 * @throws IOException when thrown from the backing writer.
85 public SchemaOrderedNormalizedNodeWriter write(final Collection<DataContainerChild<?,?>> nodes) throws IOException {
86 currentSchemaNode = root;
87 if (writeChildren(nodes, currentSchemaNode, false)) {
91 throw new IllegalStateException("It wasn't possible to serialize nodes " + nodes);
94 private SchemaOrderedNormalizedNodeWriter write(final NormalizedNode<?, ?> node, final SchemaNode dataSchemaNode)
97 //Set current schemaNode
98 try (SchemaNodeSetter sns = new SchemaNodeSetter(dataSchemaNode)) {
103 if (wasProcessedAsCompositeNode(node)) {
107 if (wasProcessAsSimpleNode(node)) {
112 throw new IllegalStateException("It wasn't possible to serialize node " + node);
115 private void write(final List<NormalizedNode<?, ?>> nodes, final SchemaNode dataSchemaNode) throws IOException {
116 for (final NormalizedNode<?, ?> node : nodes) {
117 write(node, dataSchemaNode);
122 protected boolean writeChildren(final Iterable<? extends NormalizedNode<?, ?>> children) throws IOException {
123 return writeChildren(children, currentSchemaNode, true);
126 private boolean writeChildren(final Iterable<? extends NormalizedNode<?, ?>> children,
127 final SchemaNode parentSchemaNode, final boolean endParent) throws IOException {
128 //Augmentations cannot be gotten with node.getChild so create our own structure with augmentations resolved
129 final ArrayListMultimap<QName, NormalizedNode<?, ?>> qNameToNodes = ArrayListMultimap.create();
130 for (final NormalizedNode<?, ?> child : children) {
131 if (child instanceof AugmentationNode) {
132 qNameToNodes.putAll(resolveAugmentations(child));
134 qNameToNodes.put(child.getNodeType(), child);
138 if (parentSchemaNode instanceof DataNodeContainer) {
139 if (parentSchemaNode instanceof ListSchemaNode && qNameToNodes.containsKey(parentSchemaNode.getQName())) {
140 write(qNameToNodes.get(parentSchemaNode.getQName()), parentSchemaNode);
142 for (final DataSchemaNode schemaNode : ((DataNodeContainer) parentSchemaNode).getChildNodes()) {
143 write(qNameToNodes.get(schemaNode.getQName()), schemaNode);
146 } else if (parentSchemaNode instanceof ChoiceSchemaNode) {
147 for (final CaseSchemaNode ccNode : ((ChoiceSchemaNode) parentSchemaNode).getCases()) {
148 for (final DataSchemaNode dsn : ccNode.getChildNodes()) {
149 if (qNameToNodes.containsKey(dsn.getQName())) {
150 write(qNameToNodes.get(dsn.getQName()), dsn);
155 for (final NormalizedNode<?, ?> child : children) {
160 getWriter().endNode();
165 private SchemaOrderedNormalizedNodeWriter writeLeaf(final NormalizedNode<?, ?> node) throws IOException {
166 if (wasProcessAsSimpleNode(node)) {
170 throw new IllegalStateException("It wasn't possible to serialize node " + node);
173 private ArrayListMultimap<QName, NormalizedNode<?, ?>> resolveAugmentations(final NormalizedNode<?, ?> child) {
174 final ArrayListMultimap<QName, NormalizedNode<?, ?>> resolvedAugs = ArrayListMultimap.create();
175 for (final NormalizedNode<?, ?> node : ((AugmentationNode) child).getValue()) {
176 if (node instanceof AugmentationNode) {
177 resolvedAugs.putAll(resolveAugmentations(node));
179 resolvedAugs.put(node.getNodeType(), node);
185 private final class SchemaNodeSetter implements AutoCloseable {
187 private final SchemaNode previousSchemaNode;
190 * Sets current schema node new value and store old value for later restore.
192 SchemaNodeSetter(final SchemaNode schemaNode) {
193 previousSchemaNode = SchemaOrderedNormalizedNodeWriter.this.currentSchemaNode;
194 SchemaOrderedNormalizedNodeWriter.this.currentSchemaNode = schemaNode;
198 * Restore previous schema node.
201 public void close() {
202 SchemaOrderedNormalizedNodeWriter.this.currentSchemaNode = previousSchemaNode;