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