27504f37f1fa201e8c6a5e4b7ea76c26d7f06198
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / main / java / org / opendaylight / controller / cluster / datastore / node / utils / transformer / NormalizedNodePruner.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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
9 package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Preconditions;
13 import java.io.IOException;
14 import java.net.URI;
15 import java.util.HashSet;
16 import java.util.LinkedList;
17 import java.util.List;
18 import java.util.Set;
19 import javax.xml.transform.dom.DOMSource;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
26 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
27 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
28 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
29
30 /**
31  * The NormalizedNodePruner removes all nodes from the input NormalizedNode that do not have a corresponding
32  * schema element in the passed in SchemaContext
33  *
34  */
35 public class NormalizedNodePruner implements NormalizedNodeStreamWriter {
36
37     public static final URI BASE_NAMESPACE = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0");
38     private final SimpleStack<NormalizedNodeBuilderWrapper> stack = new SimpleStack<>();
39     private NormalizedNode<?,?> normalizedNode;
40     private final Set<URI> validNamespaces;
41     private boolean sealed = false;
42
43     public NormalizedNodePruner(SchemaContext schemaContext) {
44         this(NormalizedNodePruner.namespaces(schemaContext));
45     }
46
47     public NormalizedNodePruner(Set<URI> validNamespaces) {
48         this.validNamespaces = validNamespaces;
49     }
50
51     @SuppressWarnings("unchecked")
52     @Override
53     public void leafNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, Object o) throws IOException, IllegalArgumentException {
54
55         checkNotSealed();
56
57         if(!isValidNamespace(nodeIdentifier)){
58             return;
59         }
60
61         NormalizedNodeBuilderWrapper parent = stack.peek();
62         LeafNode<Object> leafNode = Builders.leafBuilder().withNodeIdentifier(nodeIdentifier).withValue(o).build();
63         if(parent != null) {
64             parent.builder().addChild(leafNode);
65         } else {
66             // If there's no parent node then this is a stand alone LeafNode.
67             this.normalizedNode = leafNode;
68             sealed = true;
69         }
70     }
71
72     @Override
73     public void startLeafSet(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
74
75         checkNotSealed();
76
77         addBuilder(Builders.leafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
78     }
79
80     @Override
81     public void startOrderedLeafSet(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
82
83         checkNotSealed();
84
85         addBuilder(Builders.orderedLeafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
86     }
87
88     @SuppressWarnings({ "unchecked" })
89     @Override
90     public void leafSetEntryNode(QName name, Object o) throws IOException, IllegalArgumentException {
91         checkNotSealed();
92
93         if(!isValidNamespace(name)){
94             return;
95         }
96
97         NormalizedNodeBuilderWrapper parent = stack.peek();
98         if(parent != null) {
99             parent.builder().addChild(Builders.leafSetEntryBuilder().withValue(o).withNodeIdentifier(
100                     new YangInstanceIdentifier.NodeWithValue<>(parent.nodeType(), o)).build());
101         } else {
102             // If there's no parent LeafSetNode then this is a stand alone LeafSetEntryNode.
103             this.normalizedNode = Builders.leafSetEntryBuilder().withValue(o).withNodeIdentifier(
104                     new YangInstanceIdentifier.NodeWithValue<>(name, o)).build();
105             sealed = true;
106         }
107     }
108
109     @Override
110     public void startContainerNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
111
112         checkNotSealed();
113
114         addBuilder(Builders.containerBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
115     }
116
117     @Override
118     public void startYangModeledAnyXmlNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
119         throw new UnsupportedOperationException("Not implemented yet");
120     }
121
122     @Override
123     public void startUnkeyedList(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
124
125         checkNotSealed();
126
127         addBuilder(Builders.unkeyedListBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
128     }
129
130     @Override
131     public void startUnkeyedListItem(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalStateException {
132
133         checkNotSealed();
134
135         addBuilder(Builders.unkeyedListEntryBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
136     }
137
138     @Override
139     public void startMapNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
140
141         checkNotSealed();
142
143         addBuilder(Builders.mapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
144     }
145
146     @Override
147     public void startMapEntryNode(YangInstanceIdentifier.NodeIdentifierWithPredicates nodeIdentifierWithPredicates, int i) throws IOException, IllegalArgumentException {
148
149         checkNotSealed();
150
151         addBuilder(Builders.mapEntryBuilder().withNodeIdentifier(nodeIdentifierWithPredicates), nodeIdentifierWithPredicates);
152     }
153
154     @Override
155     public void startOrderedMapNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
156
157         checkNotSealed();
158
159         addBuilder(Builders.orderedMapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
160     }
161
162     @Override
163     public void startChoiceNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
164
165         checkNotSealed();
166
167         addBuilder(Builders.choiceBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
168     }
169
170     @Override
171     public void startAugmentationNode(YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier) throws IOException, IllegalArgumentException {
172
173         checkNotSealed();
174
175         addBuilder(Builders.augmentationBuilder().withNodeIdentifier(augmentationIdentifier), augmentationIdentifier);
176     }
177
178     @SuppressWarnings("unchecked")
179     @Override
180     public void anyxmlNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, Object o) throws IOException, IllegalArgumentException {
181         checkNotSealed();
182
183         if(!isValidNamespace(nodeIdentifier)){
184             return;
185         }
186
187         NormalizedNodeBuilderWrapper parent = stack.peek();
188         AnyXmlNode anyXmlNode = Builders.anyXmlBuilder().withNodeIdentifier(nodeIdentifier).
189                 withValue((DOMSource) o).build();
190         if(parent != null) {
191             parent.builder().addChild(anyXmlNode);
192         } else {
193             // If there's no parent node then this is a stand alone AnyXmlNode.
194             this.normalizedNode = anyXmlNode;
195             sealed = true;
196         }
197     }
198
199     @Override
200     public void endNode() throws IOException, IllegalStateException {
201
202         checkNotSealed();
203
204         NormalizedNodeBuilderWrapper child = stack.pop();
205
206         Preconditions.checkState(child != null, "endNode called on an empty stack");
207
208         if(!isValidNamespace(child.identifier())){
209             return;
210         }
211         NormalizedNode<?,?> normalizedNode = child.builder().build();
212
213         if(stack.size() > 0){
214             NormalizedNodeBuilderWrapper parent = stack.peek();
215             parent.builder().addChild(normalizedNode);
216         } else {
217             this.normalizedNode = normalizedNode;
218             sealed = true;
219         }
220     }
221
222     @Override
223     public void close() throws IOException {
224         sealed = true;
225     }
226
227     @Override
228     public void flush() throws IOException {
229
230     }
231
232     public NormalizedNode<?,?> normalizedNode(){
233         return normalizedNode;
234     }
235
236     private void checkNotSealed(){
237         Preconditions.checkState(!sealed, "Pruner can be used only once");
238     }
239
240     private boolean isValidNamespace(QName qName){
241         return validNamespaces.contains(qName.getNamespace());
242     }
243
244     private boolean isValidNamespace(YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier){
245         Set<QName> possibleChildNames = augmentationIdentifier.getPossibleChildNames();
246
247         for(QName qName : possibleChildNames){
248             if(isValidNamespace(qName)){
249                 return true;
250             }
251         }
252         return false;
253
254     }
255
256     private boolean isValidNamespace(YangInstanceIdentifier.PathArgument identifier){
257         if(identifier instanceof YangInstanceIdentifier.AugmentationIdentifier){
258             return isValidNamespace((YangInstanceIdentifier.AugmentationIdentifier) identifier);
259         }
260
261         return isValidNamespace(identifier.getNodeType());
262     }
263
264     private NormalizedNodeBuilderWrapper addBuilder(NormalizedNodeContainerBuilder<?,?,?,?> builder, YangInstanceIdentifier.PathArgument identifier){
265         NormalizedNodeBuilderWrapper wrapper = new NormalizedNodeBuilderWrapper(builder, identifier);
266         stack.push(wrapper);
267         return wrapper;
268     }
269
270     @VisibleForTesting
271     static class SimpleStack<E> {
272         List<E> stack = new LinkedList<>();
273
274         void push(E element){
275             stack.add(element);
276         }
277
278         E pop(){
279             if(size() == 0){
280                 return null;
281             }
282             return stack.remove(stack.size() - 1);
283         }
284
285         E peek(){
286             if(size() == 0){
287                 return null;
288             }
289
290             return stack.get(stack.size() - 1);
291         }
292
293         int size(){
294             return stack.size();
295         }
296     }
297
298     @VisibleForTesting
299     SimpleStack<NormalizedNodeBuilderWrapper> stack(){
300         return stack;
301     }
302
303     public static Set<URI> namespaces(SchemaContext schemaContext){
304         Set<URI> namespaces = new HashSet<>(schemaContext.getModules().size());
305         namespaces.add(BASE_NAMESPACE);
306         for(org.opendaylight.yangtools.yang.model.api.Module module : schemaContext.getModules()){
307             namespaces.add(module.getNamespace());
308         }
309         return namespaces;
310     }
311 }