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;
41 private final NormalizedNodeStreamWriter writer;
43 private SchemaNode currentSchemaNode;
46 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
50 * @param schemaContext
55 public SchemaOrderedNormalizedNodeWriter(final NormalizedNodeStreamWriter writer, final SchemaContext schemaContext,
56 final SchemaPath path) {
59 this.schemaContext = schemaContext;
60 final Collection<SchemaNode> schemaNodes = SchemaUtils.findParentSchemaNodesOnPath(schemaContext, path);
61 Preconditions.checkArgument(!schemaNodes.isEmpty(), "Unable to find schema node for supplied schema path: %s",
63 if (schemaNodes.size() > 1) {
64 LOG.warn("More possible schema nodes {} for supplied schema path {}", schemaNodes, path);
66 this.root = schemaNodes.iterator().next();
70 public SchemaOrderedNormalizedNodeWriter write(final NormalizedNode<?, ?> node) throws IOException {
71 if (Objects.equals(root, schemaContext)) {
72 currentSchemaNode = schemaContext.getDataChildByName(node.getNodeType());
74 currentSchemaNode = root;
76 return write(node, currentSchemaNode);
80 * Iterate over the provided collection and emit write
81 * events to the encapsulated {@link NormalizedNodeStreamWriter}.
84 * @return NormalizedNodeWriter this
85 * @throws IOException when thrown from the backing writer.
87 public SchemaOrderedNormalizedNodeWriter write(final Collection<DataContainerChild<?,?>> nodes) throws IOException {
88 currentSchemaNode = root;
89 if (writeChildren(nodes, currentSchemaNode, false)) {
93 throw new IllegalStateException("It wasn't possible to serialize nodes " + nodes);
96 private SchemaOrderedNormalizedNodeWriter write(final NormalizedNode<?, ?> node, final SchemaNode dataSchemaNode)
99 //Set current schemaNode
100 try (SchemaNodeSetter sns = new SchemaNodeSetter(dataSchemaNode)) {
105 if (wasProcessedAsCompositeNode(node)) {
109 if (wasProcessAsSimpleNode(node)) {
114 throw new IllegalStateException("It wasn't possible to serialize node " + node);
117 private void write(final List<NormalizedNode<?, ?>> nodes, final SchemaNode dataSchemaNode) throws IOException {
118 for (final NormalizedNode<?, ?> node : nodes) {
119 write(node, dataSchemaNode);
124 protected boolean writeChildren(final Iterable<? extends NormalizedNode<?, ?>> children) throws IOException {
125 return writeChildren(children, currentSchemaNode, true);
128 private boolean writeChildren(final Iterable<? extends NormalizedNode<?, ?>> children,
129 final SchemaNode parentSchemaNode, final boolean endParent) throws IOException {
130 //Augmentations cannot be gotten with node.getChild so create our own structure with augmentations resolved
131 final ArrayListMultimap<QName, NormalizedNode<?, ?>> qNameToNodes = ArrayListMultimap.create();
132 for (final NormalizedNode<?, ?> child : children) {
133 if (child instanceof AugmentationNode) {
134 qNameToNodes.putAll(resolveAugmentations(child));
136 qNameToNodes.put(child.getNodeType(), child);
140 if (parentSchemaNode instanceof DataNodeContainer) {
141 if (parentSchemaNode instanceof ListSchemaNode && qNameToNodes.containsKey(parentSchemaNode.getQName())) {
142 write(qNameToNodes.get(parentSchemaNode.getQName()), parentSchemaNode);
144 for (final DataSchemaNode schemaNode : ((DataNodeContainer) parentSchemaNode).getChildNodes()) {
145 write(qNameToNodes.get(schemaNode.getQName()), schemaNode);
148 } else if (parentSchemaNode instanceof ChoiceSchemaNode) {
149 for (final CaseSchemaNode ccNode : ((ChoiceSchemaNode) parentSchemaNode).getCases().values()) {
150 for (final DataSchemaNode dsn : ccNode.getChildNodes()) {
151 if (qNameToNodes.containsKey(dsn.getQName())) {
152 write(qNameToNodes.get(dsn.getQName()), dsn);
157 for (final NormalizedNode<?, ?> child : children) {
167 private SchemaOrderedNormalizedNodeWriter writeLeaf(final NormalizedNode<?, ?> node) throws IOException {
168 if (wasProcessAsSimpleNode(node)) {
172 throw new IllegalStateException("It wasn't possible to serialize node " + node);
175 private ArrayListMultimap<QName, NormalizedNode<?, ?>> resolveAugmentations(final NormalizedNode<?, ?> child) {
176 final ArrayListMultimap<QName, NormalizedNode<?, ?>> resolvedAugs = ArrayListMultimap.create();
177 for (final NormalizedNode<?, ?> node : ((AugmentationNode) child).getValue()) {
178 if (node instanceof AugmentationNode) {
179 resolvedAugs.putAll(resolveAugmentations(node));
181 resolvedAugs.put(node.getNodeType(), node);
187 private final class SchemaNodeSetter implements AutoCloseable {
189 private final SchemaNode previousSchemaNode;
192 * Sets current schema node new value and store old value for later restore.
194 SchemaNodeSetter(final SchemaNode schemaNode) {
195 previousSchemaNode = SchemaOrderedNormalizedNodeWriter.this.currentSchemaNode;
196 SchemaOrderedNormalizedNodeWriter.this.currentSchemaNode = schemaNode;
200 * Restore previous schema node.
203 public void close() {
204 SchemaOrderedNormalizedNodeWriter.this.currentSchemaNode = previousSchemaNode;