69e2c88d268afb5ca9e38016e16e064cacdbda68
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / utils / PruningDataTreeModification.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.utils;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Optional;
13 import java.io.IOException;
14 import org.opendaylight.controller.cluster.datastore.node.utils.transformer.NormalizedNodePruner;
15 import org.opendaylight.controller.cluster.datastore.util.AbstractDataTreeModificationCursor;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
18 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
20 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
21 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
22 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModificationCursor;
23 import org.opendaylight.yangtools.yang.data.impl.schema.tree.SchemaValidationFailedException;
24 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 /**
29  * The PruningDataTreeModification first removes all entries from the data which do not belong in the schemaContext
30  * before delegating it to the actual DataTreeModification
31  */
32 public class PruningDataTreeModification implements DataTreeModification {
33
34     private static final Logger LOG = LoggerFactory.getLogger(PruningDataTreeModification.class);
35     private DataTreeModification delegate;
36     private final SchemaContext schemaContext;
37     private final DataTree dataTree;
38
39     public PruningDataTreeModification(DataTreeModification delegate, DataTree dataTree, SchemaContext schemaContext) {
40         this.delegate = delegate;
41         this.dataTree = dataTree;
42         this.schemaContext = schemaContext;
43     }
44
45     @Override
46     public void delete(YangInstanceIdentifier yangInstanceIdentifier) {
47         try {
48             delegate.delete(yangInstanceIdentifier);
49         } catch(SchemaValidationFailedException e){
50             LOG.warn("Node at path : {} does not exist ignoring delete", yangInstanceIdentifier);
51         }
52     }
53
54     @Override
55     public void merge(YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
56         try {
57             if(YangInstanceIdentifier.EMPTY.equals(yangInstanceIdentifier)){
58                 pruneAndMergeNode(yangInstanceIdentifier, normalizedNode);
59             } else {
60                 delegate.merge(yangInstanceIdentifier, normalizedNode);
61             }
62         } catch (SchemaValidationFailedException e){
63             LOG.warn("Node at path {} was pruned during merge due to validation error: {}",
64                     yangInstanceIdentifier, e.getMessage());
65
66             pruneAndMergeNode(yangInstanceIdentifier, normalizedNode);
67         }
68
69     }
70
71     private void pruneAndMergeNode(YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
72         NormalizedNode<?,?> pruned = pruneNormalizedNode(yangInstanceIdentifier, normalizedNode);
73
74         if(pruned != null) {
75             delegate.merge(yangInstanceIdentifier, pruned);
76         }
77     }
78
79     @Override
80     public void write(YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
81         try {
82             if(YangInstanceIdentifier.EMPTY.equals(yangInstanceIdentifier)){
83                 pruneAndWriteNode(yangInstanceIdentifier, normalizedNode);
84             } else {
85                 delegate.write(yangInstanceIdentifier, normalizedNode);
86             }
87         } catch (SchemaValidationFailedException e){
88             LOG.warn("Node at path : {} was pruned during write due to validation error: {}",
89                     yangInstanceIdentifier, e.getMessage());
90
91             pruneAndWriteNode(yangInstanceIdentifier, normalizedNode);
92         }
93     }
94
95     private void pruneAndWriteNode(YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
96         NormalizedNode<?,?> pruned = pruneNormalizedNode(yangInstanceIdentifier, normalizedNode);
97
98         if(pruned != null) {
99             delegate.write(yangInstanceIdentifier, pruned);
100         }
101     }
102
103     @Override
104     public void ready() {
105         try {
106             delegate.ready();
107         } catch (SchemaValidationFailedException e) {
108             DataTreeModification newModification = dataTree.takeSnapshot().newModification();
109             delegate.applyToCursor(new PruningDataTreeModificationCursor(newModification, this));
110
111             delegate = newModification;
112             delegate.ready();
113         }
114     }
115
116     @Override
117     public void applyToCursor(DataTreeModificationCursor dataTreeModificationCursor) {
118         delegate.applyToCursor(dataTreeModificationCursor);
119     }
120
121     @Override
122     public Optional<NormalizedNode<?, ?>> readNode(YangInstanceIdentifier yangInstanceIdentifier) {
123         return delegate.readNode(yangInstanceIdentifier);
124     }
125
126     @Override
127     public DataTreeModification newModification() {
128         return new PruningDataTreeModification(delegate.newModification(), dataTree, schemaContext);
129     }
130
131     @VisibleForTesting
132     NormalizedNode<?, ?> pruneNormalizedNode(YangInstanceIdentifier path, NormalizedNode<?,?> input) {
133         NormalizedNodePruner pruner = new NormalizedNodePruner(path, schemaContext);
134         try {
135             NormalizedNodeWriter.forStreamWriter(pruner).write(input);
136         } catch (IOException ioe) {
137             LOG.error("Unexpected IOException when pruning normalizedNode", ioe);
138         }
139
140         return pruner.normalizedNode();
141     }
142
143     public DataTreeModification getResultingModification(){
144         return delegate;
145     }
146
147     private static class PruningDataTreeModificationCursor extends AbstractDataTreeModificationCursor {
148         private final DataTreeModification toModification;
149         private final PruningDataTreeModification pruningModification;
150
151         PruningDataTreeModificationCursor(DataTreeModification toModification,
152                 PruningDataTreeModification pruningModification) {
153             this.toModification = toModification;
154             this.pruningModification = pruningModification;
155         }
156
157         @Override
158         public void write(PathArgument child, NormalizedNode<?, ?> data) {
159             YangInstanceIdentifier path = current().node(child);
160             NormalizedNode<?, ?> prunedNode = pruningModification.pruneNormalizedNode(path, data);
161             if(prunedNode != null) {
162                 toModification.write(path, prunedNode);
163             }
164         }
165
166         @Override
167         public void merge(PathArgument child, NormalizedNode<?, ?> data) {
168             YangInstanceIdentifier path = current().node(child);
169             NormalizedNode<?, ?> prunedNode = pruningModification.pruneNormalizedNode(path, data);
170             if(prunedNode != null) {
171                 toModification.merge(path, prunedNode);
172             }
173         }
174
175         @Override
176         public void delete(PathArgument child) {
177             try {
178                 toModification.delete(current().node(child));
179             } catch(SchemaValidationFailedException e) {
180                 // Ignoring since we would've already logged this in the call to the original modification.
181             }
182         }
183     }
184 }