2 * Copyright (c) 2014 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 com.google.common.base.Preconditions.checkState;
12 import static java.util.Objects.requireNonNull;
14 import java.io.IOException;
15 import java.util.ArrayDeque;
16 import java.util.Deque;
17 import javax.xml.transform.dom.DOMSource;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
24 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
26 import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
27 import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeContainerBuilder;
28 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
29 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder;
30 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
31 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
32 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
33 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
34 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListNodeBuilder;
35 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUserLeafSetNodeBuilder;
36 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUserMapNodeBuilder;
37 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
40 * Implementation of {@link NormalizedNodeStreamWriter}, which constructs immutable instances of
41 * {@link NormalizedNode}s.
44 * This writer supports two modes of behaviour one is using {@link #from(NormalizedNodeResult)} where resulting
45 * NormalizedNode will be stored in supplied result object.
48 * Other mode of operation is using {@link #from(NormalizedNodeContainerBuilder)}, where all created nodes will be
49 * written to this builder.
52 * This class is not final for purposes of customization, normal users should not need to subclass it.
54 public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
55 @SuppressWarnings("rawtypes")
56 private final Deque<NormalizedNodeBuilder> builders = new ArrayDeque<>();
58 private DataSchemaNode nextSchema;
60 @SuppressWarnings("rawtypes")
61 protected ImmutableNormalizedNodeStreamWriter(final NormalizedNodeBuilder topLevelBuilder) {
62 builders.push(topLevelBuilder);
65 protected ImmutableNormalizedNodeStreamWriter(final NormalizationResultHolder holder) {
66 this(new NormalizationResultBuilder(holder));
70 * Creates a {@link NormalizedNodeStreamWriter} which creates instances of supplied {@link NormalizedNode}s
71 * and writes them to supplied builder as child nodes.
74 * Type of supplied {@link NormalizedNodeContainerBuilder} affects, which events could be emitted in order
75 * to ensure proper construction of data.
77 * @param builder Builder to which data will be written.
78 * @return {@link NormalizedNodeStreamWriter} which writes data
80 public static @NonNull NormalizedNodeStreamWriter from(final NormalizedNodeContainerBuilder<?, ?, ?, ?> builder) {
81 return new ImmutableNormalizedNodeStreamWriter(builder);
85 * Creates a {@link NormalizedNodeStreamWriter} which creates one instance of top-level {@link NormalizedNode}
86 * (type of NormalizedNode) is determined by first start event.
89 * Result is built when {@link #endNode()} associated with that start event is emitted.
92 * Writer properly creates also nested {@link NormalizedNode} instances, if their are supported inside the scope
96 * This method is useful for clients, which knows there will be one top-level node written, but does not know which
97 * type of {@link NormalizedNode} will be written.
99 * @param holder {@link NormalizationResultHolder} object which will hold result value.
100 * @return {@link NormalizedNodeStreamWriter} which will write item to supplied result holder.
102 public static @NonNull NormalizedNodeStreamWriter from(final NormalizationResultHolder holder) {
103 return new ImmutableMetadataNormalizedNodeStreamWriter(holder);
107 public void startLeafNode(final NodeIdentifier name) {
108 checkDataNodeContainer();
109 enter(name, leafNodeBuilder(nextSchema));
114 public void startLeafSet(final NodeIdentifier name, final int childSizeHint) {
115 checkDataNodeContainer();
116 enter(name, UNKNOWN_SIZE == childSizeHint ? InterningLeafSetNodeBuilder.create(nextSchema)
117 : InterningLeafSetNodeBuilder.create(nextSchema, childSizeHint));
121 public void startLeafSetEntryNode(final NodeWithValue<?> name) {
122 final NormalizedNodeBuilder<?, ?, ?> current = current();
123 checkArgument(current instanceof ImmutableLeafSetNodeBuilder
124 || current instanceof ImmutableUserLeafSetNodeBuilder || current instanceof NormalizationResultBuilder,
125 "LeafSetEntryNode is not valid for parent %s", current);
126 enter(name, leafsetEntryNodeBuilder());
131 public void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) {
132 checkDataNodeContainer();
133 enter(name, Builders.orderedLeafSetBuilder());
137 public boolean startAnyxmlNode(final NodeIdentifier name, final Class<?> objectModel) {
138 checkDataNodeContainer();
139 if (DOMSource.class.isAssignableFrom(objectModel)) {
140 enter(name, Builders.anyXmlBuilder());
148 public void startContainerNode(final NodeIdentifier name, final int childSizeHint) {
149 checkDataNodeContainer();
150 enter(name, UNKNOWN_SIZE == childSizeHint ? Builders.containerBuilder()
151 : Builders.containerBuilder(childSizeHint));
155 public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) {
156 checkDataNodeContainer();
157 enter(name, UNKNOWN_SIZE == childSizeHint ? Builders.unkeyedListBuilder()
158 : Builders.unkeyedListBuilder(childSizeHint));
162 public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) {
163 final NormalizedNodeBuilder<?, ?, ?> current = current();
164 checkArgument(current instanceof ImmutableUnkeyedListNodeBuilder
165 || current instanceof NormalizationResultBuilder);
166 enter(name, UNKNOWN_SIZE == childSizeHint ? Builders.unkeyedListEntryBuilder()
167 : Builders.unkeyedListEntryBuilder(childSizeHint));
171 public void startMapNode(final NodeIdentifier name, final int childSizeHint) {
172 checkDataNodeContainer();
173 enter(name, UNKNOWN_SIZE == childSizeHint ? Builders.mapBuilder() : Builders.mapBuilder(childSizeHint));
177 public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint) {
178 final NormalizedNodeBuilder<?, ?, ?> current = current();
179 checkArgument(current instanceof ImmutableMapNodeBuilder || current instanceof ImmutableUserMapNodeBuilder
180 || current instanceof NormalizationResultBuilder);
182 enter(identifier, UNKNOWN_SIZE == childSizeHint ? Builders.mapEntryBuilder()
183 : Builders.mapEntryBuilder(childSizeHint));
187 public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) {
188 checkDataNodeContainer();
189 enter(name, UNKNOWN_SIZE == childSizeHint ? Builders.orderedMapBuilder()
190 : Builders.orderedMapBuilder(childSizeHint));
194 public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) {
195 checkDataNodeContainer();
196 enter(name, UNKNOWN_SIZE == childSizeHint ? Builders.choiceBuilder() : Builders.choiceBuilder(childSizeHint));
200 public void startAugmentationNode(final AugmentationIdentifier identifier) {
201 checkDataNodeContainer();
202 checkArgument(!(current() instanceof ImmutableAugmentationNodeBuilder));
203 enter(identifier, Builders.augmentationBuilder());
207 public void flush() {
212 public void close() {
217 public void nextDataSchemaNode(final DataSchemaNode schema) {
218 nextSchema = requireNonNull(schema);
222 public void scalarValue(final Object value) {
223 currentScalar().withValue(value);
227 public void domSourceValue(final DOMSource value) {
228 currentScalar().withValue(value);
232 @SuppressWarnings("rawtypes")
233 public void endNode() {
234 final NormalizedNodeBuilder finishedBuilder = builders.poll();
235 checkState(finishedBuilder != null, "Node which should be closed does not exists.");
236 final NormalizedNode product = finishedBuilder.build();
243 public boolean startAnydataNode(final NodeIdentifier name, final Class<?> objectModel) throws IOException {
244 checkDataNodeContainer();
245 enter(name, Builders.anydataBuilder(objectModel));
246 // We support all object models
251 * Add a child not to the currently-open builder.
253 * @param child A new child
254 * @throws NullPointerException if {@code child} is null
255 * @throws IllegalStateException if there is no open builder
257 @SuppressWarnings({ "rawtypes", "unchecked" })
258 protected final void writeChild(final NormalizedNode child) {
259 final NormalizedNodeContainerBuilder current = currentContainer();
260 checkState(current != null, "Reached top level node, which could not be closed in this writer.");
261 current.addChild(requireNonNull(child));
264 // Exposed for ImmutableMetadataNormalizedNodeStreamWriter
265 @SuppressWarnings("rawtypes")
266 void enter(final PathArgument identifier, final NormalizedNodeBuilder next) {
267 builders.push(next.withNodeIdentifier(identifier));
271 // Exposed for ImmutableMetadataNormalizedNodeStreamWriter
272 protected final NormalizedNodeBuilder popBuilder() {
273 return builders.pop();
276 final void reset(final NormalizationResultBuilder builder) {
279 builders.push(builder);
282 private <T> ImmutableLeafNodeBuilder<T> leafNodeBuilder(final DataSchemaNode schema) {
283 final InterningLeafNodeBuilder<T> interning = InterningLeafNodeBuilder.forSchema(schema);
284 return interning != null ? interning : leafNodeBuilder();
287 <T> ImmutableLeafNodeBuilder<T> leafNodeBuilder() {
288 return new ImmutableLeafNodeBuilder<>();
291 <T> ImmutableLeafSetEntryNodeBuilder<T> leafsetEntryNodeBuilder() {
292 return ImmutableLeafSetEntryNodeBuilder.create();
295 private void checkDataNodeContainer() {
296 @SuppressWarnings("rawtypes")
297 final NormalizedNodeContainerBuilder current = currentContainer();
298 if (!(current instanceof NormalizationResultBuilder)) {
299 checkArgument(current instanceof DataContainerNodeBuilder<?, ?>, "Invalid nesting of data.");
303 @SuppressWarnings("rawtypes")
304 private NormalizedNodeBuilder current() {
305 return builders.peek();
308 @SuppressWarnings("rawtypes")
309 private NormalizedNodeContainerBuilder currentContainer() {
310 final NormalizedNodeBuilder current = current();
311 if (current == null) {
314 checkState(current instanceof NormalizedNodeContainerBuilder, "%s is not a node container", current);
315 return (NormalizedNodeContainerBuilder) current;
318 @SuppressWarnings("rawtypes")
319 private NormalizedNodeBuilder currentScalar() {
320 final NormalizedNodeBuilder current = current();
321 checkState(!(current instanceof NormalizedNodeContainerBuilder), "Unexpected node container %s", current);