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.util.ArrayDeque;
15 import java.util.Collection;
16 import java.util.Deque;
17 import javax.xml.transform.dom.DOMSource;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.opendaylight.yangtools.odlext.model.api.YangModeledAnyXmlSchemaNode;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
26 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.YangModeledAnyXmlNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
39 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
40 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
41 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
42 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
43 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
44 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
45 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAnyXmlNodeBuilder;
46 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder;
47 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
48 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
49 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
50 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
51 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
52 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
53 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedLeafSetNodeBuilder;
54 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
55 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
56 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListNodeBuilder;
57 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableYangModeledAnyXmlNodeBuilder;
58 import org.opendaylight.yangtools.yang.data.util.LeafInterner;
59 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
60 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
63 * Implementation of {@link NormalizedNodeStreamWriter}, which constructs immutable instances of
64 * {@link NormalizedNode}s.
67 * This writer supports two modes of behaviour one is using {@link #from(NormalizedNodeResult)} where resulting
68 * NormalizedNode will be stored in supplied result object.
71 * Other mode of operation is using {@link #from(NormalizedNodeContainerBuilder)}, where all created nodes will be
72 * written to this builder.
74 public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
76 @SuppressWarnings("rawtypes")
77 private final Deque<NormalizedNodeContainerBuilder> builders = new ArrayDeque<>();
78 private DataSchemaNode nextSchema;
80 @SuppressWarnings("rawtypes")
81 protected ImmutableNormalizedNodeStreamWriter(final NormalizedNodeContainerBuilder topLevelBuilder) {
82 builders.push(topLevelBuilder);
85 protected ImmutableNormalizedNodeStreamWriter(final NormalizedNodeResult result) {
86 this(new NormalizedNodeResultBuilder(result));
90 * Creates a {@link NormalizedNodeStreamWriter} which creates instances of supplied {@link NormalizedNode}s
91 * and writes them to supplied builder as child nodes.
94 * Type of supplied {@link NormalizedNodeContainerBuilder} affects, which events could be emitted in order
95 * to ensure proper construction of data.
97 * @param builder Builder to which data will be written.
98 * @return {@link NormalizedNodeStreamWriter} which writes data
100 public static @NonNull NormalizedNodeStreamWriter from(final NormalizedNodeContainerBuilder<?, ?, ?, ?> builder) {
101 return new ImmutableNormalizedNodeStreamWriter(builder);
105 * Creates a {@link NormalizedNodeStreamWriter} which creates one instance of top-level {@link NormalizedNode}
106 * (type of NormalizedNode) is determined by first start event.
109 * Result is built when {@link #endNode()} associated with that start event is emitted.
112 * Writer properly creates also nested {@link NormalizedNode} instances, if their are supported inside the scope
113 * of the first event.
116 * This method is useful for clients, which knows there will be one top-level node written, but does not know which
117 * type of {@link NormalizedNode} will be written.
119 * @param result {@link NormalizedNodeResult} object which will hold result value.
120 * @return {@link NormalizedNodeStreamWriter} which will write item to supplied result holder.
122 public static NormalizedNodeStreamWriter from(final NormalizedNodeResult result) {
123 return new ImmutableNormalizedNodeStreamWriter(result);
126 protected Deque<NormalizedNodeContainerBuilder> getBuilders() {
130 @SuppressWarnings("rawtypes")
131 protected NormalizedNodeContainerBuilder getCurrent() {
132 return builders.peek();
135 @SuppressWarnings("rawtypes")
136 private void enter(final NormalizedNodeContainerBuilder next) {
141 @SuppressWarnings("unchecked")
142 protected void writeChild(final NormalizedNode<?, ?> child) {
143 getCurrent().addChild(child);
147 @SuppressWarnings({ "rawtypes", "unchecked" })
148 public void endNode() {
149 final NormalizedNodeContainerBuilder finishedBuilder = builders.poll();
150 checkState(finishedBuilder != null, "Node which should be closed does not exists.");
151 final NormalizedNodeContainerBuilder current = getCurrent();
152 checkState(current != null, "Reached top level node, which could not be closed in this writer.");
153 final NormalizedNode<PathArgument, ?> product = finishedBuilder.build();
154 current.addChild(product);
159 public void leafNode(final NodeIdentifier name, final Object value) {
160 checkDataNodeContainer();
162 final LeafNode<Object> sample = ImmutableNodes.leafNode(name, value);
163 final LeafNode<?> node;
164 if (nextSchema instanceof LeafSchemaNode) {
165 node = LeafInterner.forSchema((LeafSchemaNode)nextSchema).intern(sample);
175 public void startLeafSet(final NodeIdentifier name, final int childSizeHint) {
176 checkDataNodeContainer();
177 final ListNodeBuilder<Object, LeafSetEntryNode<Object>> builder = UNKNOWN_SIZE == childSizeHint
178 ? InterningLeafSetNodeBuilder.create(nextSchema)
179 : InterningLeafSetNodeBuilder.create(nextSchema, childSizeHint);
180 builder.withNodeIdentifier(name);
185 public void leafSetEntryNode(final QName name, final Object value) {
186 final NormalizedNodeContainerBuilder<?, ?, ?, ?> current = getCurrent();
187 if (current instanceof ImmutableLeafSetNodeBuilder) {
188 @SuppressWarnings("unchecked")
189 ListNodeBuilder<Object, LeafSetEntryNode<Object>> builder =
190 (ImmutableLeafSetNodeBuilder<Object>) current;
191 builder.withChildValue(value);
192 } else if (current instanceof ImmutableOrderedLeafSetNodeBuilder) {
193 @SuppressWarnings("unchecked")
194 ListNodeBuilder<Object, LeafSetEntryNode<Object>> builder =
195 (ImmutableOrderedLeafSetNodeBuilder<Object>) current;
196 builder.withChildValue(value);
197 } else if (current instanceof NormalizedNodeResultBuilder) {
198 ((NormalizedNodeResultBuilder) current).addChild(ImmutableLeafSetEntryNodeBuilder.create()
199 .withNodeIdentifier(new NodeWithValue<>(name, value)).withValue(value).build());
201 throw new IllegalArgumentException("LeafSetEntryNode is not valid for parent " + current);
208 public void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) {
209 checkDataNodeContainer();
210 final ListNodeBuilder<Object, LeafSetEntryNode<Object>> builder = Builders.orderedLeafSetBuilder();
211 builder.withNodeIdentifier(name);
216 public void anyxmlNode(final NodeIdentifier name, final Object value) {
217 checkDataNodeContainer();
219 final AnyXmlNode node = ImmutableAnyXmlNodeBuilder.create().withNodeIdentifier(name)
220 .withValue((DOMSource) value).build();
227 public void startContainerNode(final NodeIdentifier name, final int childSizeHint) {
228 checkDataNodeContainer();
230 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
231 UNKNOWN_SIZE == childSizeHint ? ImmutableContainerNodeBuilder.create()
232 : ImmutableContainerNodeBuilder.create(childSizeHint);
233 enter(builder.withNodeIdentifier(name));
237 public void startYangModeledAnyXmlNode(final NodeIdentifier name, final int childSizeHint) {
238 checkDataNodeContainer();
240 checkArgument(nextSchema instanceof YangModeledAnyXmlSchemaNode,
241 "Schema of this node should be instance of YangModeledAnyXmlSchemaNode");
242 final DataContainerNodeAttrBuilder<NodeIdentifier, YangModeledAnyXmlNode> builder =
243 UNKNOWN_SIZE == childSizeHint
244 ? ImmutableYangModeledAnyXmlNodeBuilder.create((YangModeledAnyXmlSchemaNode) nextSchema)
245 : ImmutableYangModeledAnyXmlNodeBuilder.create(
246 (YangModeledAnyXmlSchemaNode) nextSchema, childSizeHint);
247 enter(builder.withNodeIdentifier(name));
251 public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) {
252 checkDataNodeContainer();
254 final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> builder =
255 UNKNOWN_SIZE == childSizeHint ? ImmutableUnkeyedListNodeBuilder.create()
256 : ImmutableUnkeyedListNodeBuilder.create(childSizeHint);
257 enter(builder.withNodeIdentifier(name));
261 public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) {
262 final NormalizedNodeContainerBuilder<?, ?, ?, ?> current = getCurrent();
263 checkArgument(current instanceof ImmutableUnkeyedListNodeBuilder
264 || current instanceof NormalizedNodeResultBuilder);
265 final DataContainerNodeAttrBuilder<NodeIdentifier, UnkeyedListEntryNode> builder =
266 UNKNOWN_SIZE == childSizeHint ? ImmutableUnkeyedListEntryNodeBuilder.create()
267 : ImmutableUnkeyedListEntryNodeBuilder.create(childSizeHint);
268 enter(builder.withNodeIdentifier(name));
272 public void startMapNode(final NodeIdentifier name, final int childSizeHint) {
273 checkDataNodeContainer();
275 final CollectionNodeBuilder<MapEntryNode, MapNode> builder = UNKNOWN_SIZE == childSizeHint
276 ? ImmutableMapNodeBuilder.create() : ImmutableMapNodeBuilder.create(childSizeHint);
277 enter(builder.withNodeIdentifier(name));
281 public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint) {
282 final NormalizedNodeContainerBuilder<?, ?, ?, ?> current = getCurrent();
283 checkArgument(current instanceof ImmutableMapNodeBuilder || current instanceof ImmutableOrderedMapNodeBuilder
284 || current instanceof NormalizedNodeResultBuilder);
286 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
287 UNKNOWN_SIZE == childSizeHint ? ImmutableMapEntryNodeBuilder.create()
288 : ImmutableMapEntryNodeBuilder.create(childSizeHint);
289 enter(builder.withNodeIdentifier(identifier));
293 public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) {
294 checkDataNodeContainer();
296 final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> builder = UNKNOWN_SIZE == childSizeHint
297 ? ImmutableOrderedMapNodeBuilder.create() : ImmutableOrderedMapNodeBuilder.create(childSizeHint);
298 enter(builder.withNodeIdentifier(name));
302 public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) {
303 checkDataNodeContainer();
305 final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> builder = UNKNOWN_SIZE == childSizeHint
306 ? ImmutableChoiceNodeBuilder.create() : ImmutableChoiceNodeBuilder.create(childSizeHint);
307 enter(builder.withNodeIdentifier(name));
311 public void startAugmentationNode(final AugmentationIdentifier identifier) {
312 checkDataNodeContainer();
313 checkArgument(!(getCurrent() instanceof ImmutableAugmentationNodeBuilder));
314 enter(Builders.augmentationBuilder().withNodeIdentifier(identifier));
317 private void checkDataNodeContainer() {
318 @SuppressWarnings("rawtypes")
319 final NormalizedNodeContainerBuilder current = getCurrent();
320 checkArgument(current instanceof DataContainerNodeBuilder || current instanceof NormalizedNodeResultBuilder,
321 "Invalid nesting of data.");
325 public void flush() {
330 public void close() {
335 public void nextDataSchemaNode(final DataSchemaNode schema) {
336 nextSchema = requireNonNull(schema);
339 final void reset(final NormalizedNodeResultBuilder builder) {
342 builders.push(builder);
345 @SuppressWarnings("rawtypes")
346 protected static final class NormalizedNodeResultBuilder implements NormalizedNodeContainerBuilder {
347 private final @NonNull NormalizedNodeResult result;
349 NormalizedNodeResultBuilder() {
350 this.result = new NormalizedNodeResult();
353 NormalizedNodeResultBuilder(final NormalizedNodeResult result) {
354 this.result = requireNonNull(result);
357 @NonNull NormalizedNodeResult result() {
362 public NormalizedNodeBuilder withValue(final Object value) {
363 throw new UnsupportedOperationException();
367 public NormalizedNodeContainerBuilder withValue(final Collection value) {
368 throw new UnsupportedOperationException();
372 public NormalizedNode build() {
373 throw new IllegalStateException("Can not close NormalizedNodeResult");
377 public NormalizedNodeContainerBuilder withNodeIdentifier(final PathArgument nodeIdentifier) {
378 throw new UnsupportedOperationException();
382 public NormalizedNodeContainerBuilder addChild(final NormalizedNode child) {
383 result.setResult(child);
388 public NormalizedNodeContainerBuilder removeChild(final PathArgument key) {
389 throw new UnsupportedOperationException();