861f11305ef4798e766b0f5518ea6e5cc69f19a5
[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.NormalizedNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
24 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
25 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
26 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
27
28 /**
29  * The NormalizedNodePruner removes all nodes from the input NormalizedNode that do not have a corresponding
30  * schema element in the passed in SchemaContext
31  *
32  */
33 public class NormalizedNodePruner implements NormalizedNodeStreamWriter {
34
35     private final SimpleStack<NormalizedNodeBuilderWrapper> stack = new SimpleStack<>();
36     private NormalizedNode<?,?> normalizedNode;
37     private final Set<URI> validNamespaces;
38     private boolean sealed = false;
39
40     public NormalizedNodePruner(SchemaContext schemaContext) {
41         validNamespaces = new HashSet<>(schemaContext.getModules().size());
42         for(org.opendaylight.yangtools.yang.model.api.Module module : schemaContext.getModules()){
43             validNamespaces.add(module.getNamespace());
44         }
45     }
46     @Override
47     public void leafNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, Object o) throws IOException, IllegalArgumentException {
48
49         checkNotSealed();
50
51         if(!isValidNamespace(nodeIdentifier)){
52             return;
53         }
54         NormalizedNodeBuilderWrapper parent = stack.peek();
55         Preconditions.checkState(parent != null, "leafNode has no parent");
56         parent.builder()
57                 .addChild(Builders.leafBuilder()
58                         .withNodeIdentifier(nodeIdentifier)
59                         .withValue(o)
60                         .build());
61     }
62
63     @Override
64     public void startLeafSet(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
65
66         checkNotSealed();
67
68         addBuilder(Builders.leafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
69     }
70
71     @Override
72     public void leafSetEntryNode(Object o) throws IOException, IllegalArgumentException {
73
74         checkNotSealed();
75
76         NormalizedNodeBuilderWrapper parent = stack.peek();
77         Preconditions.checkState(parent != null, "leafSetEntryNode has no parent");
78         if(!isValidNamespace(parent.identifier())){
79             return;
80         }
81
82         parent.builder()
83                 .addChild(Builders.leafSetEntryBuilder()
84                         .withValue(o)
85                         .withNodeIdentifier(new YangInstanceIdentifier.NodeWithValue(parent.nodeType(), o))
86                         .build());
87     }
88
89     @Override
90     public void startContainerNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
91
92         checkNotSealed();
93
94         addBuilder(Builders.containerBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
95     }
96
97     @Override
98     public void startUnkeyedList(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
99
100         checkNotSealed();
101
102         addBuilder(Builders.unkeyedListBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
103     }
104
105     @Override
106     public void startUnkeyedListItem(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalStateException {
107
108         checkNotSealed();
109
110         addBuilder(Builders.unkeyedListEntryBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
111     }
112
113     @Override
114     public void startMapNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
115
116         checkNotSealed();
117
118         addBuilder(Builders.mapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
119     }
120
121     @Override
122     public void startMapEntryNode(YangInstanceIdentifier.NodeIdentifierWithPredicates nodeIdentifierWithPredicates, int i) throws IOException, IllegalArgumentException {
123
124         checkNotSealed();
125
126         addBuilder(Builders.mapEntryBuilder().withNodeIdentifier(nodeIdentifierWithPredicates), nodeIdentifierWithPredicates);
127     }
128
129     @Override
130     public void startOrderedMapNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
131
132         checkNotSealed();
133
134         addBuilder(Builders.orderedMapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
135     }
136
137     @Override
138     public void startChoiceNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, int i) throws IOException, IllegalArgumentException {
139
140         checkNotSealed();
141
142         addBuilder(Builders.choiceBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
143     }
144
145     @Override
146     public void startAugmentationNode(YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier) throws IOException, IllegalArgumentException {
147
148         checkNotSealed();
149
150         addBuilder(Builders.augmentationBuilder().withNodeIdentifier(augmentationIdentifier), augmentationIdentifier);
151     }
152
153     @Override
154     public void anyxmlNode(YangInstanceIdentifier.NodeIdentifier nodeIdentifier, Object o) throws IOException, IllegalArgumentException {
155
156         checkNotSealed();
157
158         if(!isValidNamespace(nodeIdentifier)){
159             return;
160         }
161         NormalizedNodeBuilderWrapper parent = stack.peek();
162         Preconditions.checkState(parent != null, "anyxmlNode has no parent");
163         parent.builder().addChild(Builders.anyXmlBuilder().withNodeIdentifier(nodeIdentifier).withValue((DOMSource) o).build());
164     }
165
166     @Override
167     public void endNode() throws IOException, IllegalStateException {
168
169         checkNotSealed();
170
171         NormalizedNodeBuilderWrapper child = stack.pop();
172
173         Preconditions.checkState(child != null, "endNode called on an empty stack");
174
175         if(!isValidNamespace(child.identifier())){
176             return;
177         }
178         NormalizedNode<?,?> normalizedNode = child.builder().build();
179
180         if(stack.size() > 0){
181             NormalizedNodeBuilderWrapper parent = stack.peek();
182             parent.builder().addChild(normalizedNode);
183         } else {
184             this.normalizedNode = normalizedNode;
185             sealed = true;
186         }
187     }
188
189     @Override
190     public void close() throws IOException {
191         sealed = true;
192     }
193
194     @Override
195     public void flush() throws IOException {
196
197     }
198
199     public NormalizedNode<?,?> normalizedNode(){
200         return normalizedNode;
201     }
202
203     private void checkNotSealed(){
204         Preconditions.checkState(!sealed, "Pruner can be used only once");
205     }
206
207     private boolean isValidNamespace(QName qName){
208         return validNamespaces.contains(qName.getNamespace());
209     }
210
211     private boolean isValidNamespace(YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier){
212         Set<QName> possibleChildNames = augmentationIdentifier.getPossibleChildNames();
213
214         for(QName qName : possibleChildNames){
215             if(isValidNamespace(qName)){
216                 return true;
217             }
218         }
219         return false;
220
221     }
222
223     private boolean isValidNamespace(YangInstanceIdentifier.PathArgument identifier){
224         if(identifier instanceof YangInstanceIdentifier.AugmentationIdentifier){
225             return isValidNamespace((YangInstanceIdentifier.AugmentationIdentifier) identifier);
226         }
227
228         return isValidNamespace(identifier.getNodeType());
229     }
230
231     private NormalizedNodeBuilderWrapper addBuilder(NormalizedNodeContainerBuilder<?,?,?,?> builder, YangInstanceIdentifier.PathArgument identifier){
232         NormalizedNodeBuilderWrapper wrapper = new NormalizedNodeBuilderWrapper(builder, identifier);
233         stack.push(wrapper);
234         return wrapper;
235     }
236
237     @VisibleForTesting
238     static class SimpleStack<E> {
239         List<E> stack = new LinkedList<>();
240
241         void push(E element){
242             stack.add(element);
243         }
244
245         E pop(){
246             if(size() == 0){
247                 return null;
248             }
249             return stack.remove(stack.size() - 1);
250         }
251
252         E peek(){
253             if(size() == 0){
254                 return null;
255             }
256
257             return stack.get(stack.size() - 1);
258         }
259
260         int size(){
261             return stack.size();
262         }
263     }
264
265     @VisibleForTesting
266     SimpleStack<NormalizedNodeBuilderWrapper> stack(){
267         return stack;
268     }
269
270
271 }