f5bc6c591211faabaa5625fabc3236bf33a4c268
[yangtools.git] / data / yang-data-util / src / main / java / org / opendaylight / yangtools / yang / 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.yang.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.yang.common.QName;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
23 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedMetadata;
24 import org.opendaylight.yangtools.yang.data.api.schema.stream.ForwardingNormalizedNodeStreamWriter;
25 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
26
27 /**
28  * A simple decorator on top of a NormalizedNodeStreamWriter, which attaches NormalizedMetadata to the event stream,
29  * so that the metadata is emitted along with data.
30  */
31 final class NormalizedNodeStreamWriterMetadataDecorator extends ForwardingNormalizedNodeStreamWriter {
32     private final Deque<NormalizedMetadata> stack = new ArrayDeque<>();
33     private final NormalizedNodeStreamWriter writer;
34     private final MetadataExtension metaWriter;
35     private final NormalizedMetadata metadata;
36
37     private int absentDepth = 0;
38
39     NormalizedNodeStreamWriterMetadataDecorator(final NormalizedNodeStreamWriter writer,
40             final MetadataExtension 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 boolean startAnyxmlNode(final NodeIdentifier name, final Class<?> objectModel) throws IOException {
126         final boolean ret = super.startAnyxmlNode(name, objectModel);
127         if (ret) {
128             enterMetadataNode(name);
129         }
130         return ret;
131     }
132
133     @Override
134     public void endNode() throws IOException {
135         super.endNode();
136
137         if (absentDepth > 0) {
138             absentDepth--;
139         } else {
140             stack.pop();
141         }
142     }
143
144     private void enterMetadataNode(final PathArgument name) throws IOException {
145         if (absentDepth > 0) {
146             absentDepth++;
147             return;
148         }
149
150         final NormalizedMetadata current = stack.peek();
151         if (current != null) {
152             final NormalizedMetadata child = current.getChildren().get(name);
153             if (child != null) {
154                 enterChild(child);
155             } else {
156                 absentDepth = 1;
157             }
158         } else {
159             // Empty stack: enter first entry
160             enterChild(metadata);
161         }
162     }
163
164     private void enterChild(final NormalizedMetadata child) throws IOException {
165         final Map<QName, Object> annotations = child.getAnnotations();
166         if (!annotations.isEmpty()) {
167             metaWriter.metadata(ImmutableMap.copyOf(annotations));
168         }
169         stack.push(child);
170     }
171 }