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 com.google.common.base.Verify.verify;
12 import static java.util.Objects.requireNonNull;
14 import java.io.IOException;
15 import java.util.ArrayDeque;
16 import java.util.Deque;
17 import java.util.NoSuchElementException;
18 import java.util.Optional;
19 import javax.xml.transform.dom.DOMSource;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
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.ReusableImmutableNormalizedNodeStreamWriter;
28 import org.opendaylight.yangtools.yang.data.util.DataSchemaContext;
29 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
30 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
36 * The NormalizedNodePruner removes all nodes from the input NormalizedNode that do not have a corresponding
37 * schema element in the passed in SchemaContext.
39 abstract class AbstractNormalizedNodePruner implements NormalizedNodeStreamWriter {
47 interface WriterMethod<T extends PathArgument> {
49 void apply(ReusableImmutableNormalizedNodeStreamWriter writer, T name) throws IOException;
53 interface SizedWriterMethod<T extends PathArgument> {
55 void apply(ReusableImmutableNormalizedNodeStreamWriter writer, T name, int childSizeHint) throws IOException;
58 private static final Logger LOG = LoggerFactory.getLogger(AbstractNormalizedNodePruner.class);
60 private final Deque<DataSchemaContext> stack = new ArrayDeque<>();
61 private final ReusableImmutableNormalizedNodeStreamWriter delegate =
62 ReusableImmutableNormalizedNodeStreamWriter.create();
63 private final DataSchemaContextTree tree;
65 private DataSchemaContext nodePathSchemaNode;
66 private NormalizedNode normalizedNode;
67 private State state = State.UNITIALIZED;
70 AbstractNormalizedNodePruner(final DataSchemaContextTree tree) {
71 this.tree = requireNonNull(tree);
74 AbstractNormalizedNodePruner(final EffectiveModelContext schemaContext) {
75 this(DataSchemaContextTree.from(schemaContext));
78 final DataSchemaContextTree getTree() {
82 final void initialize(final YangInstanceIdentifier nodePath) {
83 nodePathSchemaNode = tree.findChild(nodePath).orElse(null);
85 normalizedNode = null;
92 public final void startLeafNode(final NodeIdentifier name) throws IOException {
93 enter(ReusableImmutableNormalizedNodeStreamWriter::startLeafNode, name);
97 public final void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
98 enter(ReusableImmutableNormalizedNodeStreamWriter::startLeafSet, name, childSizeHint);
102 public final void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
103 enter(ReusableImmutableNormalizedNodeStreamWriter::startOrderedLeafSet, name, childSizeHint);
107 public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
108 enter(ReusableImmutableNormalizedNodeStreamWriter::startLeafSetEntryNode, name);
112 public final void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
113 enter(ReusableImmutableNormalizedNodeStreamWriter::startContainerNode, name, childSizeHint);
117 public final void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IOException {
118 enter(ReusableImmutableNormalizedNodeStreamWriter::startUnkeyedList, name, childSizeHint);
122 public final void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
123 enter(ReusableImmutableNormalizedNodeStreamWriter::startUnkeyedListItem, name, childSizeHint);
127 public final void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
128 enter(ReusableImmutableNormalizedNodeStreamWriter::startMapNode, name, childSizeHint);
132 public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
134 enter(ReusableImmutableNormalizedNodeStreamWriter::startMapEntryNode, identifier, childSizeHint);
138 public final void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
139 enter(ReusableImmutableNormalizedNodeStreamWriter::startOrderedMapNode, name, childSizeHint);
143 public final void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
144 enter(ReusableImmutableNormalizedNodeStreamWriter::startChoiceNode, name, childSizeHint);
148 public final boolean startAnyxmlNode(final NodeIdentifier name, final Class<?> objectModel) throws IOException {
150 verify(delegate.startAnyxmlNode(name, objectModel),
151 "Unexpected failure to stream DOMSource node %s model %s", name, objectModel);
157 public final boolean startAnydataNode(final NodeIdentifier name, final Class<?> objectModel) throws IOException {
158 // FIXME: we do not support anydata nodes yet
163 public final void domSourceValue(final DOMSource value) throws IOException {
166 delegate.domSourceValue(value);
171 public final void scalarValue(final Object value) throws IOException {
174 delegate.scalarValue(translateScalar(currentSchema(), value));
178 Object translateScalar(final DataSchemaContext context, final Object value) {
179 // Default is pass-through
184 public final void endNode() throws IOException {
190 } catch (NoSuchElementException e) {
191 throw new IllegalStateException("endNode called on an empty stack", e);
197 // Still at unknown, do not attempt to create result
202 if (stack.isEmpty()) {
203 final var result = delegate.result();
204 normalizedNode = result != null ? result.data() : null;
205 state = State.CLOSED;
210 public final void close() throws IOException {
211 state = State.CLOSED;
217 public final void flush() throws IOException {
222 * Return the resulting normalized node.
224 * @return Resulting node for the path, if it was not pruned
225 * @throws IllegalStateException if this pruner has not been closed
227 public final Optional<NormalizedNode> getResult() {
228 checkState(state == State.CLOSED, "Cannot get result in state %s", state);
229 return Optional.ofNullable(normalizedNode);
232 private void checkNotSealed() {
233 checkState(state == State.OPEN, "Illegal operation in state %s", state);
236 private boolean enter(final PathArgument name) {
240 LOG.debug("Skipping child {} in unknown subtree", name);
245 final DataSchemaContext schema;
246 final DataSchemaContext parent = currentSchema();
247 if (parent != null) {
248 schema = parent instanceof DataSchemaContext.Composite compositeParent ? compositeParent.childByArg(name)
251 schema = nodePathSchemaNode;
254 if (schema == null) {
255 LOG.debug("Schema not found for {}", name);
261 final DataSchemaNode dataSchema = schema.dataSchemaNode();
262 if (dataSchema != null) {
263 delegate.nextDataSchemaNode(dataSchema);
268 final <A extends PathArgument> void enter(final WriterMethod<A> method, final A name) throws IOException {
270 method.apply(delegate, name);
274 final <A extends PathArgument> void enter(final SizedWriterMethod<A> method, final A name, final int size)
277 method.apply(delegate, name, size);
281 final DataSchemaContext currentSchema() {