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.data.api.YangInstanceIdentifier.AugmentationIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
25 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.YangModeledAnyXmlNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
36 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
37 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
38 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
39 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
40 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
41 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
42 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAnyXmlNodeBuilder;
43 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAugmentationNodeBuilder;
44 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder;
45 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
46 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
47 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
48 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
49 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
50 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedLeafSetNodeBuilder;
51 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableOrderedMapNodeBuilder;
52 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
53 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListNodeBuilder;
54 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableYangModeledAnyXmlNodeBuilder;
55 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
58 * Implementation of {@link NormalizedNodeStreamWriter}, which constructs immutable instances of
59 * {@link NormalizedNode}s.
62 * This writer supports two modes of behaviour one is using {@link #from(NormalizedNodeResult)} where resulting
63 * NormalizedNode will be stored in supplied result object.
66 * Other mode of operation is using {@link #from(NormalizedNodeContainerBuilder)}, where all created nodes will be
67 * written to this builder.
69 public class ImmutableNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
71 @SuppressWarnings("rawtypes")
72 private final Deque<NormalizedNodeBuilder> builders = new ArrayDeque<>();
73 private DataSchemaNode nextSchema;
75 @SuppressWarnings("rawtypes")
76 protected ImmutableNormalizedNodeStreamWriter(final NormalizedNodeContainerBuilder topLevelBuilder) {
77 builders.push(topLevelBuilder);
80 protected ImmutableNormalizedNodeStreamWriter(final NormalizedNodeResult result) {
81 this(new NormalizedNodeResultBuilder(result));
85 * Creates a {@link NormalizedNodeStreamWriter} which creates instances of supplied {@link NormalizedNode}s
86 * and writes them to supplied builder as child nodes.
89 * Type of supplied {@link NormalizedNodeContainerBuilder} affects, which events could be emitted in order
90 * to ensure proper construction of data.
92 * @param builder Builder to which data will be written.
93 * @return {@link NormalizedNodeStreamWriter} which writes data
95 public static @NonNull NormalizedNodeStreamWriter from(final NormalizedNodeContainerBuilder<?, ?, ?, ?> builder) {
96 return new ImmutableNormalizedNodeStreamWriter(builder);
100 * Creates a {@link NormalizedNodeStreamWriter} which creates one instance of top-level {@link NormalizedNode}
101 * (type of NormalizedNode) is determined by first start event.
104 * Result is built when {@link #endNode()} associated with that start event is emitted.
107 * Writer properly creates also nested {@link NormalizedNode} instances, if their are supported inside the scope
108 * of the first event.
111 * This method is useful for clients, which knows there will be one top-level node written, but does not know which
112 * type of {@link NormalizedNode} will be written.
114 * @param result {@link NormalizedNodeResult} object which will hold result value.
115 * @return {@link NormalizedNodeStreamWriter} which will write item to supplied result holder.
117 public static NormalizedNodeStreamWriter from(final NormalizedNodeResult result) {
118 return new ImmutableNormalizedNodeStreamWriter(result);
121 @SuppressWarnings("rawtypes")
122 protected NormalizedNodeBuilder getCurrent() {
123 return builders.peek();
126 @SuppressWarnings("rawtypes")
127 protected final NormalizedNodeContainerBuilder getCurrentContainer() {
128 final NormalizedNodeBuilder current = getCurrent();
129 if (current == null) {
132 checkState(current instanceof NormalizedNodeContainerBuilder, "%s is not a node container", current);
133 return (NormalizedNodeContainerBuilder) current;
136 @SuppressWarnings("rawtypes")
137 protected NormalizedNodeBuilder getCurrentScalar() {
138 final NormalizedNodeBuilder current = getCurrent();
139 checkState(!(current instanceof NormalizedNodeContainerBuilder), "Unexpected node container %s", current);
143 @SuppressWarnings("rawtypes")
144 private void enter(final NormalizedNodeBuilder next) {
149 @SuppressWarnings("unchecked")
150 protected void writeChild(final NormalizedNode<?, ?> child) {
151 getCurrentContainer().addChild(child);
155 @SuppressWarnings({"rawtypes","unchecked"})
156 public void endNode() {
157 final NormalizedNodeBuilder finishedBuilder = builders.poll();
158 checkState(finishedBuilder != null, "Node which should be closed does not exists.");
159 final NormalizedNodeContainerBuilder current = getCurrentContainer();
160 checkState(current != null, "Reached top level node, which could not be closed in this writer.");
161 final NormalizedNode<PathArgument, ?> product = finishedBuilder.build();
162 current.addChild(product);
167 public void startLeafNode(final NodeIdentifier name) {
168 checkDataNodeContainer();
169 enter(InterningLeafNodeBuilder.forSchema(nextSchema).withNodeIdentifier(name));
174 public void startLeafSet(final NodeIdentifier name, final int childSizeHint) {
175 checkDataNodeContainer();
176 final ListNodeBuilder<Object, LeafSetEntryNode<Object>> builder = UNKNOWN_SIZE == childSizeHint
177 ? InterningLeafSetNodeBuilder.create(nextSchema)
178 : InterningLeafSetNodeBuilder.create(nextSchema, childSizeHint);
179 builder.withNodeIdentifier(name);
184 public void startLeafSetEntryNode(final NodeWithValue<?> name) {
185 @SuppressWarnings("rawtypes")
186 final NormalizedNodeBuilder current = getCurrent();
187 checkArgument(current instanceof ImmutableOrderedLeafSetNodeBuilder
188 || current instanceof ImmutableLeafSetNodeBuilder, "LeafSetEntryNode is not valid for parent %s", current);
189 enter(ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(name));
194 public void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) {
195 checkDataNodeContainer();
196 final ListNodeBuilder<Object, LeafSetEntryNode<Object>> builder = Builders.orderedLeafSetBuilder();
197 builder.withNodeIdentifier(name);
202 public void startAnyxmlNode(final NodeIdentifier name) {
203 checkDataNodeContainer();
204 enter(ImmutableAnyXmlNodeBuilder.create().withNodeIdentifier(name));
209 public void startContainerNode(final NodeIdentifier name, final int childSizeHint) {
210 checkDataNodeContainer();
212 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> builder =
213 UNKNOWN_SIZE == childSizeHint ? ImmutableContainerNodeBuilder.create()
214 : ImmutableContainerNodeBuilder.create(childSizeHint);
215 enter(builder.withNodeIdentifier(name));
219 public void startYangModeledAnyXmlNode(final NodeIdentifier name, final int childSizeHint) {
220 checkDataNodeContainer();
222 checkArgument(nextSchema instanceof YangModeledAnyXmlSchemaNode,
223 "Schema of this node should be instance of YangModeledAnyXmlSchemaNode");
224 final DataContainerNodeAttrBuilder<NodeIdentifier, YangModeledAnyXmlNode> builder =
225 UNKNOWN_SIZE == childSizeHint
226 ? ImmutableYangModeledAnyXmlNodeBuilder.create((YangModeledAnyXmlSchemaNode) nextSchema)
227 : ImmutableYangModeledAnyXmlNodeBuilder.create(
228 (YangModeledAnyXmlSchemaNode) nextSchema, childSizeHint);
229 enter(builder.withNodeIdentifier(name));
233 public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) {
234 checkDataNodeContainer();
236 final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> builder =
237 UNKNOWN_SIZE == childSizeHint ? ImmutableUnkeyedListNodeBuilder.create()
238 : ImmutableUnkeyedListNodeBuilder.create(childSizeHint);
239 enter(builder.withNodeIdentifier(name));
243 public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) {
244 checkArgument(getCurrent() instanceof NormalizedNodeResultBuilder
245 || getCurrent() instanceof ImmutableUnkeyedListNodeBuilder);
246 final DataContainerNodeAttrBuilder<NodeIdentifier, UnkeyedListEntryNode> builder =
247 UNKNOWN_SIZE == childSizeHint ? ImmutableUnkeyedListEntryNodeBuilder.create()
248 : ImmutableUnkeyedListEntryNodeBuilder.create(childSizeHint);
249 enter(builder.withNodeIdentifier(name));
253 public void startMapNode(final NodeIdentifier name, final int childSizeHint) {
254 checkDataNodeContainer();
256 final CollectionNodeBuilder<MapEntryNode, MapNode> builder = UNKNOWN_SIZE == childSizeHint
257 ? ImmutableMapNodeBuilder.create() : ImmutableMapNodeBuilder.create(childSizeHint);
258 enter(builder.withNodeIdentifier(name));
262 public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint) {
263 if (!(getCurrent() instanceof NormalizedNodeResultBuilder)) {
264 checkArgument(getCurrent() instanceof ImmutableMapNodeBuilder
265 || getCurrent() instanceof ImmutableOrderedMapNodeBuilder);
268 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
269 UNKNOWN_SIZE == childSizeHint ? ImmutableMapEntryNodeBuilder.create()
270 : ImmutableMapEntryNodeBuilder.create(childSizeHint);
271 enter(builder.withNodeIdentifier(identifier));
275 public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) {
276 checkDataNodeContainer();
278 final CollectionNodeBuilder<MapEntryNode, OrderedMapNode> builder = UNKNOWN_SIZE == childSizeHint
279 ? ImmutableOrderedMapNodeBuilder.create() : ImmutableOrderedMapNodeBuilder.create(childSizeHint);
280 enter(builder.withNodeIdentifier(name));
284 public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) {
285 checkDataNodeContainer();
287 final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> builder = UNKNOWN_SIZE == childSizeHint
288 ? ImmutableChoiceNodeBuilder.create() : ImmutableChoiceNodeBuilder.create(childSizeHint);
289 enter(builder.withNodeIdentifier(name));
293 public void startAugmentationNode(final AugmentationIdentifier identifier) {
294 checkDataNodeContainer();
295 checkArgument(!(getCurrent() instanceof ImmutableAugmentationNodeBuilder));
296 enter(Builders.augmentationBuilder().withNodeIdentifier(identifier));
299 private void checkDataNodeContainer() {
300 @SuppressWarnings("rawtypes")
301 final NormalizedNodeContainerBuilder current = getCurrentContainer();
302 if (!(current instanceof NormalizedNodeResultBuilder)) {
303 checkArgument(current instanceof DataContainerNodeBuilder<?, ?>, "Invalid nesting of data.");
307 @SuppressWarnings("rawtypes")
308 protected static final class NormalizedNodeResultBuilder implements NormalizedNodeContainerBuilder {
310 private final NormalizedNodeResult result;
312 public NormalizedNodeResultBuilder(final NormalizedNodeResult result) {
313 this.result = result;
317 public NormalizedNodeBuilder withValue(final Object value) {
318 throw new UnsupportedOperationException();
322 public NormalizedNodeContainerBuilder withValue(final Collection value) {
323 throw new UnsupportedOperationException();
327 public NormalizedNode build() {
328 throw new IllegalStateException("Can not close NormalizedNodeResult");
332 public NormalizedNodeContainerBuilder withNodeIdentifier(final PathArgument nodeIdentifier) {
333 throw new UnsupportedOperationException();
337 public NormalizedNodeContainerBuilder addChild(final NormalizedNode child) {
338 result.setResult(child);
343 public NormalizedNodeContainerBuilder removeChild(final PathArgument key) {
344 throw new UnsupportedOperationException();
349 public void flush() {
354 public void close() {
359 public void nextDataSchemaNode(final DataSchemaNode schema) {
360 nextSchema = requireNonNull(schema);
364 public void scalarValue(final Object value) {
365 getCurrentScalar().withValue(value);
369 public void domSourceValue(final DOMSource value) {
370 getCurrentScalar().withValue(value);