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 static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.collect.ArrayListMultimap;
14 import com.google.common.collect.Multimap;
15 import java.io.IOException;
16 import java.util.Collection;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
20 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
22 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
23 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
26 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
28 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
31 import org.opendaylight.yangtools.yang.model.api.SchemaTreeInference;
32 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
33 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
34 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
37 * This is an iterator over a {@link NormalizedNode}. Unlike {@link NormalizedNodeWriter}, this iterates over elements
38 * in the order as they are defined in YANG file.
40 public class SchemaOrderedNormalizedNodeWriter extends NormalizedNodeWriter {
41 private final EffectiveModelContext schemaContext;
42 private final SchemaNode root;
44 private SchemaNode currentSchemaNode;
47 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
49 * @param writer Back-end writer
50 * @param schemaContext Associated {@link EffectiveModelContext}
52 public SchemaOrderedNormalizedNodeWriter(final NormalizedNodeStreamWriter writer,
53 final EffectiveModelContext schemaContext) {
55 root = this.schemaContext = requireNonNull(schemaContext);
58 private SchemaOrderedNormalizedNodeWriter(final NormalizedNodeStreamWriter writer,
59 final SchemaInferenceStack stack) {
61 schemaContext = stack.getEffectiveModelContext();
63 if (!stack.isEmpty()) {
64 final EffectiveStatement<?, ?> current = stack.currentStatement();
65 // FIXME: this should be one of NormalizedNodeContainer/NotificationDefinition/OperationDefinition
66 checkArgument(current instanceof SchemaNode, "Instantiating at %s is not supported", current);
67 root = (SchemaNode) current;
74 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
76 * @param writer Back-end writer
77 * @param schemaContext Associated {@link EffectiveModelContext}
78 * @param path root path
80 public SchemaOrderedNormalizedNodeWriter(final NormalizedNodeStreamWriter writer,
81 final EffectiveModelContext schemaContext, final Absolute path) {
82 this(writer, SchemaInferenceStack.of(schemaContext, path));
86 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
88 * @param writer Back-end writer
89 * @param rootInference A SchemaTreeInference pointing to the root element
91 public SchemaOrderedNormalizedNodeWriter(final NormalizedNodeStreamWriter writer,
92 final SchemaTreeInference rootInference) {
93 this(writer, SchemaInferenceStack.ofInference(rootInference));
97 * Create a new writer backed by a {@link NormalizedNodeStreamWriter}.
99 * @param writer Back-end writer
100 * @param schemaContext Associated {@link EffectiveModelContext}
101 * @param path root path
102 * @deprecated Use either one of the alternative constructors instead.
104 @Deprecated(since = "7.0.11")
105 public SchemaOrderedNormalizedNodeWriter(final NormalizedNodeStreamWriter writer,
106 final EffectiveModelContext schemaContext, final SchemaPath path) {
107 this(writer, SchemaInferenceStack.ofSchemaPath(schemaContext, path));
111 public SchemaOrderedNormalizedNodeWriter write(final NormalizedNode node) throws IOException {
112 if (schemaContext.equals(root)) {
113 currentSchemaNode = schemaContext.dataChildByName(node.getIdentifier().getNodeType());
115 currentSchemaNode = root;
117 return write(node, currentSchemaNode);
121 * Iterate over the provided collection and emit write
122 * events to the encapsulated {@link NormalizedNodeStreamWriter}.
125 * @return NormalizedNodeWriter this
126 * @throws IOException when thrown from the backing writer.
128 public SchemaOrderedNormalizedNodeWriter write(final Collection<DataContainerChild> nodes) throws IOException {
129 currentSchemaNode = root;
130 if (writeChildren(nodes, currentSchemaNode, false)) {
134 throw new IllegalStateException("It wasn't possible to serialize nodes " + nodes);
137 private SchemaOrderedNormalizedNodeWriter write(final NormalizedNode node, final SchemaNode dataSchemaNode)
140 //Set current schemaNode
141 try (SchemaNodeSetter sns = new SchemaNodeSetter(dataSchemaNode)) {
146 if (wasProcessedAsCompositeNode(node)) {
150 if (wasProcessAsSimpleNode(node)) {
155 throw new IllegalStateException("It wasn't possible to serialize node " + node);
158 private void write(final Collection<NormalizedNode> nodes, final SchemaNode dataSchemaNode) throws IOException {
159 for (final NormalizedNode node : nodes) {
160 write(node, dataSchemaNode);
165 protected boolean writeChildren(final Iterable<? extends NormalizedNode> children) throws IOException {
166 return writeChildren(children, currentSchemaNode, true);
169 private boolean writeChildren(final Iterable<? extends NormalizedNode> children, final SchemaNode parentSchemaNode,
170 final boolean endParent) throws IOException {
171 // Augmentations cannot be gotten with node.getChild so create our own structure with augmentations resolved
172 final Multimap<QName, NormalizedNode> qnameToNodes = ArrayListMultimap.create();
173 for (final NormalizedNode child : children) {
174 putChild(qnameToNodes, child);
177 if (parentSchemaNode instanceof DataNodeContainer) {
178 if (parentSchemaNode instanceof ListSchemaNode && qnameToNodes.containsKey(parentSchemaNode.getQName())) {
179 write(qnameToNodes.get(parentSchemaNode.getQName()), parentSchemaNode);
181 for (final DataSchemaNode schemaNode : ((DataNodeContainer) parentSchemaNode).getChildNodes()) {
182 write(qnameToNodes.get(schemaNode.getQName()), schemaNode);
185 } else if (parentSchemaNode instanceof ChoiceSchemaNode) {
186 for (final CaseSchemaNode ccNode : ((ChoiceSchemaNode) parentSchemaNode).getCases()) {
187 for (final DataSchemaNode dsn : ccNode.getChildNodes()) {
188 if (qnameToNodes.containsKey(dsn.getQName())) {
189 write(qnameToNodes.get(dsn.getQName()), dsn);
194 for (final NormalizedNode child : children) {
199 getWriter().endNode();
204 private SchemaOrderedNormalizedNodeWriter writeLeaf(final NormalizedNode node) throws IOException {
205 if (wasProcessAsSimpleNode(node)) {
209 throw new IllegalStateException("It wasn't possible to serialize node " + node);
212 private static void putChild(final Multimap<QName, NormalizedNode> qnameToNodes, final NormalizedNode child) {
213 if (child instanceof AugmentationNode) {
214 for (DataContainerChild grandChild : ((AugmentationNode) child).body()) {
215 putChild(qnameToNodes, grandChild);
218 qnameToNodes.put(child.getIdentifier().getNodeType(), child);
222 private final class SchemaNodeSetter implements AutoCloseable {
224 private final SchemaNode previousSchemaNode;
227 * Sets current schema node new value and store old value for later restore.
229 SchemaNodeSetter(final SchemaNode schemaNode) {
230 previousSchemaNode = currentSchemaNode;
231 currentSchemaNode = schemaNode;
235 * Restore previous schema node.
238 public void close() {
239 currentSchemaNode = previousSchemaNode;