Merge "Bug 499: Added support for change listeners."
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / md / sal / dom / store / impl / tree / NodeModification.java
1 /*
2  * Copyright (c) 2014 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.md.sal.dom.store.impl.tree;
9
10 import static com.google.common.base.Preconditions.checkState;
11
12 import java.util.LinkedHashMap;
13 import java.util.Map;
14
15 import org.opendaylight.yangtools.concepts.Identifiable;
16 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
17 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
18
19 import com.google.common.base.Optional;
20
21 /**
22  * Node Modification Node and Tree
23  *
24  * Tree which structurally resembles data tree and captures client modifications
25  * to the data store tree.
26  *
27  * This tree is lazily created and populated via {@link #modifyChild(PathArgument)}
28  * and {@link StoreMetadataNode} which represents original state {@link #getOriginal()}.
29  *
30  */
31 public class NodeModification implements StoreTreeNode<NodeModification>, Identifiable<PathArgument> {
32
33     private final PathArgument identifier;
34     private ModificationType modificationType = ModificationType.UNMODIFIED;
35
36
37     private final Optional<StoreMetadataNode> original;
38
39     private NormalizedNode<?, ?> value;
40
41     private StoreMetadataNode snapshotCache;
42
43     private final Map<PathArgument, NodeModification> childModification;
44
45     private boolean sealed = false;
46
47     protected NodeModification(final PathArgument identifier, final Optional<StoreMetadataNode> original) {
48         this.identifier = identifier;
49         this.original = original;
50         childModification = new LinkedHashMap<>();
51     }
52
53     /**
54      *
55      *
56      * @return
57      */
58     public NormalizedNode<?, ?> getWritenValue() {
59         return value;
60     }
61
62     @Override
63     public PathArgument getIdentifier() {
64         return identifier;
65     }
66
67     /**
68      *
69      * Returns original store metadata
70      * @return original store metadata
71      */
72     public final Optional<StoreMetadataNode> getOriginal() {
73         return original;
74     }
75
76     /**
77      * Returns modification type
78      *
79      * @return modification type
80      */
81     public final ModificationType getModificationType() {
82         return modificationType;
83     }
84
85     /**
86      *
87      * Returns child modification if child was modified
88      *
89      * @return Child modification if direct child or it's subtree
90      *  was modified.
91      *
92      */
93     @Override
94     public Optional<NodeModification> getChild(final PathArgument child) {
95         return Optional.<NodeModification> fromNullable(childModification.get(child));
96     }
97
98     /**
99      *
100      * Returns child modification if child was modified, creates {@link NodeModification}
101      * for child otherwise.
102      *
103      * If this node's {@link ModificationType} is {@link ModificationType#UNMODIFIED}
104      * changes modification type to {@link ModificationType#SUBTREE_MODIFIED}
105      *
106      * @param child
107      * @return {@link NodeModification} for specified child, with {@link #getOriginal()}
108      *  containing child metadata if child was present in original data.
109      */
110     public synchronized NodeModification modifyChild(final PathArgument child) {
111         checkSealed();
112         if(modificationType == ModificationType.UNMODIFIED) {
113             updateModificationType(ModificationType.SUBTREE_MODIFIED);
114         }
115         final NodeModification potential = childModification.get(child);
116         if (potential != null) {
117             return potential;
118         }
119         Optional<StoreMetadataNode> currentMetadata = Optional.absent();
120         if(original.isPresent()) {
121             currentMetadata = original.get().getChild(child);
122         }
123         NodeModification newlyCreated = new NodeModification(child,currentMetadata);
124         childModification.put(child, newlyCreated);
125         return newlyCreated;
126     }
127
128     /**
129      *
130      * Returns all recorded direct child modification
131      *
132      * @return all recorded direct child modifications
133      */
134     public Iterable<NodeModification> getModifications() {
135         return childModification.values();
136     }
137
138
139     /**
140      *
141      * Records a delete for associated node.
142      *
143      */
144     public synchronized void delete() {
145         checkSealed();
146         updateModificationType(ModificationType.DELETE);
147         childModification.clear();
148         this.value = null;
149     }
150
151     /**
152      *
153      * Records a write for associated node.
154      *
155      * @param value
156      */
157     public synchronized void write(final NormalizedNode<?, ?> value) {
158         checkSealed();
159         updateModificationType(ModificationType.WRITE);
160         childModification.clear();
161         this.value = value;
162     }
163
164     private void checkSealed() {
165         checkState(!sealed, "Node Modification is sealed. No further changes allowed.");
166     }
167
168     public synchronized void seal() {
169         sealed = true;
170         for(NodeModification child : childModification.values()) {
171             child.seal();
172         }
173     }
174
175     private void clearSnapshot() {
176         snapshotCache = null;
177     }
178
179     public boolean hasAdditionalModifications() {
180         return !childModification.isEmpty();
181     }
182
183     public void updateModificationType(final ModificationType type) {
184         modificationType = type;
185         clearSnapshot();
186     }
187
188     @Override
189     public String toString() {
190         return "NodeModification [identifier=" + identifier + ", modificationType="
191                 + modificationType + ", value=" + value + ", childModification=" + childModification + "]";
192     }
193
194     public static NodeModification createUnmodified(final StoreMetadataNode metadataTree) {
195         return new NodeModification(metadataTree.getIdentifier(), Optional.of(metadataTree));
196     }
197
198 }