Add ImmutableNormalizedNode implementation
[yangtools.git] / yang / rfc7952-data-util / src / main / java / org / opendaylight / yangtools / rfc7952 / data / util / NormalizedNodeStreamWriterMetadataDecorator.java
1 /*
2  * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.rfc7952.data.util;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.collect.ImmutableMap;
13 import java.io.IOException;
14 import java.util.ArrayDeque;
15 import java.util.Deque;
16 import java.util.Map;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.yangtools.rfc7952.data.api.NormalizedMetadata;
19 import org.opendaylight.yangtools.rfc7952.data.api.NormalizedMetadataStreamWriter;
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.stream.ForwardingNormalizedNodeStreamWriter;
27 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
28
29 /**
30  * A simple decorator on top of a NormalizedNodeStreamWriter, which attaches NormalizedMetadata to the event stream,
31  * so that the metadata is emitted along with data.
32  */
33 final class NormalizedNodeStreamWriterMetadataDecorator extends ForwardingNormalizedNodeStreamWriter {
34     private final Deque<NormalizedMetadata> stack = new ArrayDeque<>();
35     private final NormalizedMetadataStreamWriter metaWriter;
36     private final NormalizedNodeStreamWriter writer;
37     private final NormalizedMetadata metadata;
38
39     NormalizedNodeStreamWriterMetadataDecorator(final NormalizedNodeStreamWriter writer,
40             final NormalizedMetadataStreamWriter metaWriter, final NormalizedMetadata metadata) {
41         this.writer = requireNonNull(writer);
42         this.metaWriter = requireNonNull(metaWriter);
43         this.metadata = requireNonNull(metadata);
44     }
45
46     @Override
47     protected NormalizedNodeStreamWriter delegate() {
48         return writer;
49     }
50
51     @Override
52     public void startLeafNode(final NodeIdentifier name) throws IOException {
53         super.startLeafNode(name);
54         enterMetadataNode(name);
55     }
56
57     @Override
58     public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
59         super.startLeafSet(name, childSizeHint);
60         enterMetadataNode(name);
61     }
62
63     @Override
64     public void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
65         super.startOrderedLeafSet(name, childSizeHint);
66         enterMetadataNode(name);
67     }
68
69     @Override
70     public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
71         super.startLeafSetEntryNode(name);
72         enterMetadataNode(name);
73     }
74
75     @Override
76     public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
77         super.startContainerNode(name, childSizeHint);
78         enterMetadataNode(name);
79     }
80
81     @Override
82     public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IOException {
83         super.startUnkeyedList(name, childSizeHint);
84         enterMetadataNode(name);
85     }
86
87     @Override
88     public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
89         super.startUnkeyedListItem(name, childSizeHint);
90         enterMetadataNode(name);
91     }
92
93     @Override
94     public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
95         super.startMapNode(name, childSizeHint);
96         enterMetadataNode(name);
97     }
98
99     @Override
100     public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
101             throws IOException {
102         super.startMapEntryNode(identifier, childSizeHint);
103         enterMetadataNode(identifier);
104     }
105
106     @Override
107     public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
108         super.startOrderedMapNode(name, childSizeHint);
109         enterMetadataNode(name);
110     }
111
112     @Override
113     public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
114         super.startChoiceNode(name, childSizeHint);
115         enterMetadataNode(name);
116     }
117
118     @Override
119     public void startAugmentationNode(final AugmentationIdentifier identifier) throws IOException {
120         super.startAugmentationNode(identifier);
121         enterMetadataNode(identifier);
122     }
123
124     @Override
125     public void startAnyxmlNode(final NodeIdentifier name) throws IOException {
126         super.startAnyxmlNode(name);
127         enterMetadataNode(name);
128     }
129
130     @Override
131     public void startYangModeledAnyXmlNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
132         super.startYangModeledAnyXmlNode(name, childSizeHint);
133         enterMetadataNode(name);
134     }
135
136     @Override
137     public void endNode() throws IOException {
138         super.endNode();
139         stack.pop();
140     }
141
142     private void enterMetadataNode(final PathArgument name) throws IOException {
143         final NormalizedMetadata child = findMetadata(name);
144         if (child != null) {
145             emitAnnotations(child.getAnnotations());
146         }
147         stack.push(child);
148     }
149
150     private @Nullable NormalizedMetadata findMetadata(final PathArgument name) {
151         final NormalizedMetadata current = stack.peek();
152         if (current == null) {
153             // This may either be the first entry or unattached metadata nesting
154             return stack.isEmpty() ? metadata : null;
155         }
156         return current.getChild(name).orElse(null);
157     }
158
159     private void emitAnnotations(final Map<QName, Object> annotations) throws IOException {
160         if (!annotations.isEmpty()) {
161             metaWriter.metadata(ImmutableMap.copyOf(annotations));
162         }
163     }
164 }