Move data extensions to data/
[yangtools.git] / data / 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.opendaylight.yangtools.rfc7952.data.api.NormalizedMetadata;
18 import org.opendaylight.yangtools.rfc7952.data.api.StreamWriterMetadataExtension;
19 import org.opendaylight.yangtools.yang.common.QName;
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.stream.ForwardingNormalizedNodeStreamWriter;
26 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
27
28 /**
29  * A simple decorator on top of a NormalizedNodeStreamWriter, which attaches NormalizedMetadata to the event stream,
30  * so that the metadata is emitted along with data.
31  */
32 final class NormalizedNodeStreamWriterMetadataDecorator extends ForwardingNormalizedNodeStreamWriter {
33     private final Deque<NormalizedMetadata> stack = new ArrayDeque<>();
34     private final StreamWriterMetadataExtension metaWriter;
35     private final NormalizedNodeStreamWriter writer;
36     private final NormalizedMetadata metadata;
37
38     private int absentDepth = 0;
39
40     NormalizedNodeStreamWriterMetadataDecorator(final NormalizedNodeStreamWriter writer,
41             final StreamWriterMetadataExtension metaWriter, final NormalizedMetadata metadata) {
42         this.writer = requireNonNull(writer);
43         this.metaWriter = requireNonNull(metaWriter);
44         this.metadata = requireNonNull(metadata);
45     }
46
47     @Override
48     protected NormalizedNodeStreamWriter delegate() {
49         return writer;
50     }
51
52     @Override
53     public void startLeafNode(final NodeIdentifier name) throws IOException {
54         super.startLeafNode(name);
55         enterMetadataNode(name);
56     }
57
58     @Override
59     public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
60         super.startLeafSet(name, childSizeHint);
61         enterMetadataNode(name);
62     }
63
64     @Override
65     public void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
66         super.startOrderedLeafSet(name, childSizeHint);
67         enterMetadataNode(name);
68     }
69
70     @Override
71     public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
72         super.startLeafSetEntryNode(name);
73         enterMetadataNode(name);
74     }
75
76     @Override
77     public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
78         super.startContainerNode(name, childSizeHint);
79         enterMetadataNode(name);
80     }
81
82     @Override
83     public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IOException {
84         super.startUnkeyedList(name, childSizeHint);
85         enterMetadataNode(name);
86     }
87
88     @Override
89     public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
90         super.startUnkeyedListItem(name, childSizeHint);
91         enterMetadataNode(name);
92     }
93
94     @Override
95     public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
96         super.startMapNode(name, childSizeHint);
97         enterMetadataNode(name);
98     }
99
100     @Override
101     public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
102             throws IOException {
103         super.startMapEntryNode(identifier, childSizeHint);
104         enterMetadataNode(identifier);
105     }
106
107     @Override
108     public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
109         super.startOrderedMapNode(name, childSizeHint);
110         enterMetadataNode(name);
111     }
112
113     @Override
114     public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
115         super.startChoiceNode(name, childSizeHint);
116         enterMetadataNode(name);
117     }
118
119     @Override
120     public void startAugmentationNode(final AugmentationIdentifier identifier) throws IOException {
121         super.startAugmentationNode(identifier);
122         enterMetadataNode(identifier);
123     }
124
125     @Override
126     public boolean startAnyxmlNode(final NodeIdentifier name, final Class<?> objectModel) throws IOException {
127         final boolean ret = super.startAnyxmlNode(name, objectModel);
128         if (ret) {
129             enterMetadataNode(name);
130         }
131         return ret;
132     }
133
134     @Override
135     public void endNode() throws IOException {
136         super.endNode();
137
138         if (absentDepth > 0) {
139             absentDepth--;
140         } else {
141             stack.pop();
142         }
143     }
144
145     private void enterMetadataNode(final PathArgument name) throws IOException {
146         if (absentDepth > 0) {
147             absentDepth++;
148             return;
149         }
150
151         final NormalizedMetadata current = stack.peek();
152         if (current != null) {
153             final NormalizedMetadata child = current.getChildren().get(name);
154             if (child != null) {
155                 enterChild(child);
156             } else {
157                 absentDepth = 1;
158             }
159         } else {
160             // Empty stack: enter first entry
161             enterChild(metadata);
162         }
163     }
164
165     private void enterChild(final NormalizedMetadata child) throws IOException {
166         final Map<QName, Object> annotations = child.getAnnotations();
167         if (!annotations.isEmpty()) {
168             metaWriter.metadata(ImmutableMap.copyOf(annotations));
169         }
170         stack.push(child);
171     }
172 }