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.utils;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.collect.ForwardingObject;
14 import java.io.IOException;
15 import java.util.Optional;
16 import org.opendaylight.controller.cluster.datastore.node.utils.transformer.ReusableNormalizedNodePruner;
17 import org.opendaylight.controller.cluster.datastore.util.AbstractDataTreeModificationCursor;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
20 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
22 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
23 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
24 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModificationCursor;
25 import org.opendaylight.yangtools.yang.data.impl.schema.tree.SchemaValidationFailedException;
26 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
31 * The PruningDataTreeModification first removes all entries from the data which do not belong in the schemaContext
32 * before delegating it to the actual DataTreeModification.
34 public abstract class PruningDataTreeModification extends ForwardingObject implements DataTreeModification {
36 * A PruningDataTreeModification which always performs pruning before attempting an operation. This sacrifices
37 * performance to ensure all data has passed through the pruner -- such that data adaptations are performed.
39 public static final class Proactive extends PruningDataTreeModification {
40 public Proactive(final DataTreeModification delegate, final DataTree dataTree,
41 final ReusableNormalizedNodePruner pruner) {
42 super(delegate, dataTree, pruner);
46 public void merge(final YangInstanceIdentifier path, final NormalizedNode data) {
47 pruneAndMergeNode(path, data);
51 public void write(final YangInstanceIdentifier path, final NormalizedNode data) {
52 pruneAndWriteNode(path, data);
56 PruningDataTreeModification createNew(final DataTreeModification delegate, final DataTree dataTree,
57 final ReusableNormalizedNodePruner pruner) {
58 return new Proactive(delegate, dataTree, pruner);
63 * A PruningDataTreeModification which performs pruning only when an operation results in an
64 * {@link SchemaValidationFailedException}. This offers superior performance in the normal case of not needing
67 public static final class Reactive extends PruningDataTreeModification {
68 public Reactive(final DataTreeModification delegate, final DataTree dataTree,
69 final ReusableNormalizedNodePruner pruner) {
70 super(delegate, dataTree, pruner);
74 public void merge(final YangInstanceIdentifier path, final NormalizedNode data) {
76 pruneAndMergeNode(path, data);
81 delegate().merge(path, data);
82 } catch (SchemaValidationFailedException e) {
83 LOG.warn("Node at path {} was pruned during merge due to validation error: {}", path, e.getMessage());
84 pruneAndMergeNode(path, data);
89 public void write(final YangInstanceIdentifier path, final NormalizedNode data) {
91 pruneAndWriteNode(path, data);
96 delegate().write(path, data);
97 } catch (SchemaValidationFailedException e) {
98 LOG.warn("Node at path : {} was pruned during write due to validation error: {}", path, e.getMessage());
99 pruneAndWriteNode(path, data);
104 PruningDataTreeModification createNew(final DataTreeModification delegate, final DataTree dataTree,
105 final ReusableNormalizedNodePruner pruner) {
106 return new Reactive(delegate, dataTree, pruner);
110 private static final Logger LOG = LoggerFactory.getLogger(PruningDataTreeModification.class);
112 private final ReusableNormalizedNodePruner pruner;
113 private final DataTree dataTree;
115 private DataTreeModification delegate;
117 PruningDataTreeModification(final DataTreeModification delegate, final DataTree dataTree,
118 final ReusableNormalizedNodePruner pruner) {
119 this.delegate = requireNonNull(delegate);
120 this.dataTree = requireNonNull(dataTree);
121 this.pruner = requireNonNull(pruner);
125 protected final DataTreeModification delegate() {
130 public final EffectiveModelContext getEffectiveModelContext() {
131 return delegate.getEffectiveModelContext();
135 public final void delete(final YangInstanceIdentifier path) {
137 delegate.delete(path);
138 } catch (SchemaValidationFailedException e) {
139 LOG.warn("Node at path : {} does not exist ignoring delete", path);
143 final void pruneAndMergeNode(final YangInstanceIdentifier path, final NormalizedNode data) {
144 final NormalizedNode pruned = pruneNormalizedNode(path, data);
145 if (pruned != null) {
146 delegate.merge(path, pruned);
150 final void pruneAndWriteNode(final YangInstanceIdentifier path, final NormalizedNode data) {
151 final NormalizedNode pruned = pruneNormalizedNode(path, data);
152 if (pruned != null) {
153 delegate.write(path, pruned);
158 public final void ready() {
161 } catch (SchemaValidationFailedException e) {
162 DataTreeModification newModification = dataTree.takeSnapshot().newModification();
163 delegate.applyToCursor(new PruningDataTreeModificationCursor(newModification, this));
165 delegate = newModification;
171 public final void applyToCursor(final DataTreeModificationCursor dataTreeModificationCursor) {
172 delegate.applyToCursor(dataTreeModificationCursor);
176 public final Optional<NormalizedNode> readNode(final YangInstanceIdentifier yangInstanceIdentifier) {
177 return delegate.readNode(yangInstanceIdentifier);
181 public final DataTreeModification newModification() {
182 return createNew(delegate.newModification(), dataTree, pruner.duplicate());
186 final NormalizedNode pruneNormalizedNode(final YangInstanceIdentifier path, final NormalizedNode input) {
187 pruner.initializeForPath(path);
189 NormalizedNodeWriter.forStreamWriter(pruner).write(input);
190 } catch (IOException ioe) {
191 LOG.error("Unexpected IOException when pruning normalizedNode", ioe);
195 return pruner.getResult().orElse(null);
198 abstract PruningDataTreeModification createNew(DataTreeModification delegate, DataTree dataTree,
199 ReusableNormalizedNodePruner pruner);
201 private static final class PruningDataTreeModificationCursor extends AbstractDataTreeModificationCursor {
202 private final DataTreeModification toModification;
203 private final PruningDataTreeModification pruningModification;
205 PruningDataTreeModificationCursor(final DataTreeModification toModification,
206 final PruningDataTreeModification pruningModification) {
207 this.toModification = toModification;
208 this.pruningModification = pruningModification;
212 public void write(final PathArgument child, final NormalizedNode data) {
213 final YangInstanceIdentifier path = current().node(child);
214 final NormalizedNode prunedNode = pruningModification.pruneNormalizedNode(path, data);
215 if (prunedNode != null) {
216 toModification.write(path, prunedNode);
221 public void merge(final PathArgument child, final NormalizedNode data) {
222 final YangInstanceIdentifier path = current().node(child);
223 final NormalizedNode prunedNode = pruningModification.pruneNormalizedNode(path, data);
224 if (prunedNode != null) {
225 toModification.merge(path, prunedNode);
230 public void delete(final PathArgument child) {
232 toModification.delete(current().node(child));
233 } catch (SchemaValidationFailedException e) {
234 // Ignoring since we would've already logged this in the call to the original modification.