2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
10 import static com.google.common.base.Preconditions.checkState;
11 import static java.util.Objects.requireNonNull;
13 import java.util.ArrayDeque;
14 import java.util.Deque;
15 import java.util.NoSuchElementException;
16 import java.util.Optional;
17 import javax.xml.transform.dom.DOMSource;
18 import org.opendaylight.yangtools.yang.common.QName;
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.AnyXmlNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
29 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
30 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
31 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
32 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 * The NormalizedNodePruner removes all nodes from the input NormalizedNode that do not have a corresponding
39 * schema element in the passed in SchemaContext.
41 abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWriter {
48 private static final Logger LOG = LoggerFactory.getLogger(AbstractNormalizedNodePruner.class);
50 private final Deque<NormalizedNodeBuilderWrapper> stack = new ArrayDeque<>();
51 private final DataSchemaContextTree tree;
53 private DataSchemaContextNode<?> nodePathSchemaNode;
54 private State state = State.UNITIALIZED;
56 // FIXME: package-private to support unguarded NormalizedNodePruner access
57 NormalizedNode<?, ?> normalizedNode;
59 AbstractNormalizedNodePruner(final DataSchemaContextTree tree) {
60 this.tree = requireNonNull(tree);
63 AbstractNormalizedNodePruner(final SchemaContext schemaContext) {
64 this(DataSchemaContextTree.from(schemaContext));
67 final DataSchemaContextTree getTree() {
71 final void initialize(final YangInstanceIdentifier nodePath) {
72 nodePathSchemaNode = tree.findChild(nodePath).orElse(null);
73 normalizedNode = null;
78 @SuppressWarnings("unchecked")
80 public void leafNode(final NodeIdentifier nodeIdentifier, final Object value) {
83 NormalizedNodeBuilderWrapper parent = stack.peek();
84 LeafNode<Object> leafNode = Builders.leafBuilder().withNodeIdentifier(nodeIdentifier).withValue(value).build();
86 if (hasValidSchema(nodeIdentifier.getNodeType(), parent)) {
87 parent.builder().addChild(leafNode);
90 // If there's no parent node then this is a stand alone LeafNode.
91 if (nodePathSchemaNode != null) {
92 this.normalizedNode = leafNode;
100 public void startLeafSet(final NodeIdentifier nodeIdentifier, final int count) {
101 addBuilder(Builders.leafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
105 public void startOrderedLeafSet(final NodeIdentifier nodeIdentifier, final int str) {
106 addBuilder(Builders.orderedLeafSetBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
109 @SuppressWarnings("unchecked")
111 public void leafSetEntryNode(final QName name, final Object value) {
114 NormalizedNodeBuilderWrapper parent = stack.peek();
115 if (parent != null) {
116 if (hasValidSchema(name, parent)) {
117 parent.builder().addChild(Builders.leafSetEntryBuilder().withValue(value)
118 .withNodeIdentifier(new NodeWithValue<>(parent.nodeType(), value))
122 // If there's no parent LeafSetNode then this is a stand alone
124 if (nodePathSchemaNode != null) {
125 this.normalizedNode = Builders.leafSetEntryBuilder().withValue(value).withNodeIdentifier(
126 new NodeWithValue<>(name, value)).build();
129 state = State.CLOSED;
134 public void startContainerNode(final NodeIdentifier nodeIdentifier, final int count) {
135 addBuilder(Builders.containerBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
139 public void startYangModeledAnyXmlNode(final NodeIdentifier nodeIdentifier, final int count) {
140 throw new UnsupportedOperationException("Not implemented yet");
144 public void startUnkeyedList(final NodeIdentifier nodeIdentifier, final int count) {
145 addBuilder(Builders.unkeyedListBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
149 public void startUnkeyedListItem(final NodeIdentifier nodeIdentifier, final int count) {
150 addBuilder(Builders.unkeyedListEntryBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
154 public void startMapNode(final NodeIdentifier nodeIdentifier, final int count) {
155 addBuilder(Builders.mapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
159 public void startMapEntryNode(final NodeIdentifierWithPredicates nodeIdentifierWithPredicates, final int count) {
160 addBuilder(Builders.mapEntryBuilder().withNodeIdentifier(nodeIdentifierWithPredicates),
161 nodeIdentifierWithPredicates);
165 public void startOrderedMapNode(final NodeIdentifier nodeIdentifier, final int count) {
166 addBuilder(Builders.orderedMapBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
170 public void startChoiceNode(final NodeIdentifier nodeIdentifier, final int count) {
171 addBuilder(Builders.choiceBuilder().withNodeIdentifier(nodeIdentifier), nodeIdentifier);
175 public void startAugmentationNode(final AugmentationIdentifier augmentationIdentifier) {
176 addBuilder(Builders.augmentationBuilder().withNodeIdentifier(augmentationIdentifier), augmentationIdentifier);
179 @SuppressWarnings("unchecked")
181 public void anyxmlNode(final NodeIdentifier nodeIdentifier, final Object value) {
184 NormalizedNodeBuilderWrapper parent = stack.peek();
185 AnyXmlNode anyXmlNode = Builders.anyXmlBuilder().withNodeIdentifier(nodeIdentifier).withValue((DOMSource) value)
187 if (parent != null) {
188 if (hasValidSchema(nodeIdentifier.getNodeType(), parent)) {
189 parent.builder().addChild(anyXmlNode);
192 // If there's no parent node then this is a stand alone AnyXmlNode.
193 if (nodePathSchemaNode != null) {
194 this.normalizedNode = anyXmlNode;
197 state = State.CLOSED;
201 @SuppressWarnings("unchecked")
203 public void endNode() {
206 final NormalizedNodeBuilderWrapper child;
209 } catch (NoSuchElementException e) {
210 throw new IllegalStateException("endNode called on an empty stack", e);
213 if (child.getSchema() == null) {
214 LOG.debug("Schema not found for {}", child.identifier());
215 if (stack.isEmpty()) {
216 normalizedNode = null;
217 state = State.CLOSED;
222 final NormalizedNode<?, ?> newNode = child.builder().build();
223 final NormalizedNodeBuilderWrapper parent = stack.peek();
224 if (parent == null) {
225 normalizedNode = newNode;
226 state = State.CLOSED;
228 parent.builder().addChild(newNode);
233 public void close() {
234 state = State.CLOSED;
239 public void flush() {
244 * Return the resulting normalized node.
246 * @return Resulting node for the path, if it was not pruned
247 * @throws IllegalStateException if this pruner has not been closed
249 public final Optional<NormalizedNode<?, ?>> getResult() {
250 checkState(state == State.CLOSED, "Cannot get result in state %s", state);
251 return Optional.ofNullable(normalizedNode);
254 private void checkNotSealed() {
255 checkState(state == State.OPEN, "Illegal operation in state %s", state);
258 private static boolean hasValidSchema(final QName name, final NormalizedNodeBuilderWrapper parent) {
259 final DataSchemaContextNode<?> parentSchema = parent.getSchema();
260 final boolean valid = parentSchema != null && parentSchema.getChild(name) != null;
262 LOG.debug("Schema not found for {}", name);
268 private NormalizedNodeBuilderWrapper addBuilder(final NormalizedNodeContainerBuilder<?, ?, ?, ?> builder,
269 final PathArgument identifier) {
272 final DataSchemaContextNode<?> schemaNode;
273 final NormalizedNodeBuilderWrapper parent = stack.peek();
274 if (parent != null) {
275 final DataSchemaContextNode<?> parentSchema = parent.getSchema();
276 schemaNode = parentSchema == null ? null : parentSchema.getChild(identifier);
278 schemaNode = nodePathSchemaNode;
281 NormalizedNodeBuilderWrapper wrapper = new NormalizedNodeBuilderWrapper(builder, identifier, schemaNode);