Bump yangtools to 3.0.0
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / main / java / org / opendaylight / controller / cluster / datastore / node / utils / transformer / AbstractNormalizedNodePruner.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 package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
9
10 import static com.google.common.base.Preconditions.checkState;
11 import static java.util.Objects.requireNonNull;
12
13 import java.io.IOException;
14 import java.util.ArrayDeque;
15 import java.util.Deque;
16 import java.util.NoSuchElementException;
17 import java.util.Optional;
18 import javax.xml.transform.dom.DOMSource;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
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.NormalizedNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
27 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
28 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
29 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
30 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
31 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * The NormalizedNodePruner removes all nodes from the input NormalizedNode that do not have a corresponding
37  * schema element in the passed in SchemaContext.
38  */
39 abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWriter {
40     enum State {
41         UNITIALIZED,
42         OPEN,
43         CLOSED;
44     }
45
46     private static final Logger LOG = LoggerFactory.getLogger(AbstractNormalizedNodePruner.class);
47
48     private final Deque<NormalizedNodeBuilderWrapper> stack = new ArrayDeque<>();
49     private final DataSchemaContextTree tree;
50
51     private DataSchemaContextNode<?> nodePathSchemaNode;
52     private State state = State.UNITIALIZED;
53
54     // FIXME: package-private to support unguarded NormalizedNodePruner access
55     NormalizedNode<?, ?> normalizedNode;
56
57     AbstractNormalizedNodePruner(final DataSchemaContextTree tree) {
58         this.tree = requireNonNull(tree);
59     }
60
61     AbstractNormalizedNodePruner(final SchemaContext schemaContext) {
62         this(DataSchemaContextTree.from(schemaContext));
63     }
64
65     final DataSchemaContextTree getTree() {
66         return tree;
67     }
68
69     final void initialize(final YangInstanceIdentifier nodePath) {
70         nodePathSchemaNode = tree.findChild(nodePath).orElse(null);
71         normalizedNode = null;
72         stack.clear();
73         state = State.OPEN;
74     }
75
76     @Override
77     public void startLeafNode(final NodeIdentifier name) {
78         addBuilder(Builders.leafBuilder().withNodeIdentifier(name), name);
79     }
80
81     @Override
82     public void startLeafSet(final NodeIdentifier nodeIdentifier, final int count) {
83         addBuilder(Builders.leafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
84     }
85
86     @Override
87     public void startOrderedLeafSet(final NodeIdentifier nodeIdentifier, final int str) {
88         addBuilder(Builders.orderedLeafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
89     }
90
91     @Override
92     public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
93         addBuilder(Builders.leafSetEntryBuilder().withNodeIdentifier(name), name);
94     }
95
96     @Override
97     public void startContainerNode(final NodeIdentifier nodeIdentifier, final int count) {
98         addBuilder(Builders.containerBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
99     }
100
101     @Override
102     public void startYangModeledAnyXmlNode(final NodeIdentifier nodeIdentifier, final int count) {
103         throw new UnsupportedOperationException("Not implemented yet");
104     }
105
106     @Override
107     public void startUnkeyedList(final NodeIdentifier nodeIdentifier, final int count) {
108         addBuilder(Builders.unkeyedListBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
109     }
110
111     @Override
112     public void startUnkeyedListItem(final NodeIdentifier nodeIdentifier, final int count) {
113         addBuilder(Builders.unkeyedListEntryBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
114     }
115
116     @Override
117     public void startMapNode(final NodeIdentifier nodeIdentifier, final int count) {
118         addBuilder(Builders.mapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
119     }
120
121     @Override
122     public void startMapEntryNode(final NodeIdentifierWithPredicates nodeIdentifierWithPredicates, final int count) {
123         addBuilder(Builders.mapEntryBuilder().withNodeIdentifier(nodeIdentifierWithPredicates),
124                 nodeIdentifierWithPredicates);
125     }
126
127     @Override
128     public void startOrderedMapNode(final NodeIdentifier nodeIdentifier, final int count) {
129         addBuilder(Builders.orderedMapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
130     }
131
132     @Override
133     public void startChoiceNode(final NodeIdentifier nodeIdentifier, final int count) {
134         addBuilder(Builders.choiceBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
135     }
136
137     @Override
138     public void startAugmentationNode(final AugmentationIdentifier augmentationIdentifier) {
139         addBuilder(Builders.augmentationBuilder().withNodeIdentifier(augmentationIdentifier), augmentationIdentifier);
140     }
141
142     @Override
143     public void startAnyxmlNode(final NodeIdentifier name) {
144         addBuilder(Builders.anyXmlBuilder().withNodeIdentifier(name), name);
145     }
146
147     @Override
148     public void domSourceValue(final DOMSource value) {
149         setValue(value);
150     }
151
152     @Override
153     public void scalarValue(final Object value) {
154         setValue(value);
155     }
156
157     @Override
158     public void endNode() {
159         checkNotSealed();
160
161         final NormalizedNodeBuilderWrapper child;
162         try {
163             child = stack.pop();
164         } catch (NoSuchElementException e) {
165             throw new IllegalStateException("endNode called on an empty stack", e);
166         }
167
168         if (child.getSchema() == null) {
169             LOG.debug("Schema not found for {}", child.identifier());
170             if (stack.isEmpty()) {
171                 normalizedNode = null;
172                 state = State.CLOSED;
173             }
174             return;
175         }
176
177         final NormalizedNode<?, ?> newNode = child.build();
178         final NormalizedNodeBuilderWrapper parent = stack.peek();
179         if (parent == null) {
180             normalizedNode = newNode;
181             state = State.CLOSED;
182         } else {
183             parent.addChild(newNode);
184         }
185     }
186
187     @Override
188     public void close() {
189         state = State.CLOSED;
190         stack.clear();
191     }
192
193     @Override
194     public void flush() {
195         // No-op
196     }
197
198     /**
199      * Return the resulting normalized node.
200      *
201      * @return Resulting node for the path, if it was not pruned
202      * @throws IllegalStateException if this pruner has not been closed
203      */
204     public final Optional<NormalizedNode<?, ?>> getResult() {
205         checkState(state == State.CLOSED, "Cannot get result in state %s", state);
206         return Optional.ofNullable(normalizedNode);
207     }
208
209     private void checkNotSealed() {
210         checkState(state == State.OPEN, "Illegal operation in state %s", state);
211     }
212
213     private void setValue(final Object value) {
214         checkNotSealed();
215         final NormalizedNodeBuilderWrapper current = stack.peek();
216         checkState(current != null, "Attempted to set value %s while no node is open", value);
217         current.setValue(value);
218     }
219
220     private <T extends NormalizedNodeBuilder<?, ?, ?>> NormalizedNodeBuilderWrapper addBuilder(final T builder,
221             final PathArgument identifier) {
222         checkNotSealed();
223
224         final DataSchemaContextNode<?> schemaNode;
225         final NormalizedNodeBuilderWrapper parent = stack.peek();
226         if (parent != null) {
227             schemaNode = parent.childSchema(identifier);
228         } else {
229             schemaNode = nodePathSchemaNode;
230         }
231
232         NormalizedNodeBuilderWrapper wrapper = new NormalizedNodeBuilderWrapper(builder, identifier, schemaNode);
233         stack.push(wrapper);
234         return wrapper;
235     }
236 }