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 / DataChangeEventResolver.java
1 package org.opendaylight.controller.md.sal.dom.store.impl;
2
3 import static org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.builder;
4 import static org.opendaylight.controller.md.sal.dom.store.impl.StoreUtils.append;
5 import static org.opendaylight.controller.md.sal.dom.store.impl.tree.TreeNodeUtils.getChild;
6
7 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
8 import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder;
9 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerRegistrationNode;
10 import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification;
11 import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode;
12 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerRegistrationNode.DataChangeListenerRegistration;
13 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
14 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
15 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
16
17 import com.google.common.base.Optional;
18 import com.google.common.collect.ImmutableList;
19 import com.google.common.collect.ImmutableSet;
20
21 public class DataChangeEventResolver {
22
23     private static final DOMImmutableDataChangeEvent NO_CHANGE = builder().build();
24     private InstanceIdentifier rootPath;
25     private ListenerRegistrationNode listenerRoot;
26     private NodeModification modificationRoot;
27     private Optional<StoreMetadataNode> beforeRoot;
28     private Optional<StoreMetadataNode> afterRoot;
29     private final ImmutableList.Builder<ChangeListenerNotifyTask> tasks = ImmutableList.builder();
30
31     protected InstanceIdentifier getRootPath() {
32         return rootPath;
33     }
34
35     protected DataChangeEventResolver setRootPath(final InstanceIdentifier rootPath) {
36         this.rootPath = rootPath;
37         return this;
38     }
39
40     protected ListenerRegistrationNode getListenerRoot() {
41         return listenerRoot;
42     }
43
44     protected DataChangeEventResolver setListenerRoot(final ListenerRegistrationNode listenerRoot) {
45         this.listenerRoot = listenerRoot;
46         return this;
47     }
48
49     protected NodeModification getModificationRoot() {
50         return modificationRoot;
51     }
52
53     protected DataChangeEventResolver setModificationRoot(final NodeModification modificationRoot) {
54         this.modificationRoot = modificationRoot;
55         return this;
56     }
57
58     protected Optional<StoreMetadataNode> getBeforeRoot() {
59         return beforeRoot;
60     }
61
62     protected DataChangeEventResolver setBeforeRoot(final Optional<StoreMetadataNode> beforeRoot) {
63         this.beforeRoot = beforeRoot;
64         return this;
65     }
66
67     protected Optional<StoreMetadataNode> getAfterRoot() {
68         return afterRoot;
69     }
70
71     protected DataChangeEventResolver setAfterRoot(final Optional<StoreMetadataNode> afterRoot) {
72         this.afterRoot = afterRoot;
73         return this;
74     }
75
76     public Iterable<ChangeListenerNotifyTask> resolve() {
77         resolveAnyChangeEvent(rootPath, Optional.of(listenerRoot), modificationRoot, beforeRoot, afterRoot);
78         return tasks.build();
79     }
80
81     private DOMImmutableDataChangeEvent resolveAnyChangeEvent(final InstanceIdentifier path,
82             final Optional<ListenerRegistrationNode> listeners, final NodeModification modification,
83             final Optional<StoreMetadataNode> before, final Optional<StoreMetadataNode> after) {
84         // No listeners are present in listener registration subtree
85         // no before and after state is present
86         if (!before.isPresent() && !after.isPresent()) {
87             return NO_CHANGE;
88         }
89         switch (modification.getModificationType()) {
90         case SUBTREE_MODIFIED:
91             return resolveSubtreeChangeEvent(path, listeners, modification, before.get(), after.get());
92         case WRITE:
93             if (before.isPresent()) {
94                 return resolveReplacedEvent(path, listeners, modification, before.get(), after.get());
95             } else {
96                 return resolveCreateEvent(path, listeners, after.get());
97             }
98         case DELETE:
99             return resolveDeleteEvent(path, listeners, before.get());
100         default:
101             return NO_CHANGE;
102         }
103
104     }
105
106     /**
107      * Resolves create events deep down the interest listener tree.
108      *
109      *
110      * @param path
111      * @param listeners
112      * @param afterState
113      * @return
114      */
115     private DOMImmutableDataChangeEvent resolveCreateEvent(final InstanceIdentifier path,
116             final Optional<ListenerRegistrationNode> listeners, final StoreMetadataNode afterState) {
117         final NormalizedNode<?, ?> node = afterState.getData();
118         Builder builder = builder().setAfter(node).addCreated(path, node);
119
120         for (StoreMetadataNode child : afterState.getChildren()) {
121             PathArgument childId = child.getIdentifier();
122             Optional<ListenerRegistrationNode> childListeners = getChild(listeners, childId);
123
124             InstanceIdentifier childPath = StoreUtils.append(path, childId);
125             builder.merge(resolveCreateEvent(childPath, childListeners, child));
126         }
127         DOMImmutableDataChangeEvent event = builder.build();
128         if (listeners.isPresent()) {
129             addNotifyTask(listeners.get().getListeners(), event);
130         }
131         return event;
132     }
133
134     private DOMImmutableDataChangeEvent resolveDeleteEvent(final InstanceIdentifier path,
135             final Optional<ListenerRegistrationNode> listeners, final StoreMetadataNode beforeState) {
136         final NormalizedNode<?, ?> node = beforeState.getData();
137         Builder builder = builder().setBefore(node).addRemoved(path, node);
138
139         for (StoreMetadataNode child : beforeState.getChildren()) {
140             PathArgument childId = child.getIdentifier();
141             Optional<ListenerRegistrationNode> childListeners = getChild(listeners, childId);
142             InstanceIdentifier childPath = StoreUtils.append(path, childId);
143             builder.merge(resolveDeleteEvent(childPath, childListeners, child));
144         }
145         DOMImmutableDataChangeEvent event = builder.build();
146         if (listeners.isPresent()) {
147             addNotifyTask(listeners.get().getListeners(), event);
148         }
149         return event;
150
151     }
152
153     private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final InstanceIdentifier path,
154             final Optional<ListenerRegistrationNode> listeners, final NodeModification modification,
155             final StoreMetadataNode before, final StoreMetadataNode after) {
156
157         Builder one = builder().setBefore(before.getData()).setAfter(after.getData());
158
159         Builder subtree = builder();
160
161         for (NodeModification childMod : modification.getModifications()) {
162             PathArgument childId = childMod.getIdentifier();
163             InstanceIdentifier childPath = append(path, childId);
164             Optional<ListenerRegistrationNode> childListen = getChild(listeners, childId);
165
166             Optional<StoreMetadataNode> childBefore = before.getChild(childId);
167             Optional<StoreMetadataNode> childAfter = after.getChild(childId);
168
169             switch (childMod.getModificationType()) {
170             case WRITE:
171             case DELETE:
172                 one.merge(resolveAnyChangeEvent(childPath, childListen, childMod, childBefore, childBefore));
173                 break;
174             case SUBTREE_MODIFIED:
175                 subtree.merge(resolveSubtreeChangeEvent(childPath, childListen, childMod, childBefore.get(),
176                         childAfter.get()));
177                 break;
178             }
179         }
180         DOMImmutableDataChangeEvent oneChangeEvent = one.build();
181         subtree.merge(oneChangeEvent);
182         DOMImmutableDataChangeEvent subtreeEvent = subtree.build();
183         if (listeners.isPresent()) {
184             addNotifyTask(listeners.get(), DataChangeScope.ONE, oneChangeEvent);
185             addNotifyTask(listeners.get(), DataChangeScope.SUBTREE, subtreeEvent);
186         }
187         return subtreeEvent;
188     }
189
190     private DOMImmutableDataChangeEvent resolveReplacedEvent(final InstanceIdentifier path,
191             final Optional<ListenerRegistrationNode> listeners, final NodeModification modification,
192             final StoreMetadataNode before, final StoreMetadataNode after) {
193         // FIXME Add task
194         return builder().build();
195     }
196
197     private void addNotifyTask(final ListenerRegistrationNode listenerRegistrationNode, final DataChangeScope one,
198             final DOMImmutableDataChangeEvent event) {
199
200
201
202     }
203
204     private void addNotifyTask(final Iterable<DataChangeListenerRegistration<?>> listeners,
205             final DOMImmutableDataChangeEvent event) {
206         tasks .add(new ChangeListenerNotifyTask(ImmutableSet.copyOf(listeners),event));
207     }
208
209     public static DataChangeEventResolver create() {
210         return new DataChangeEventResolver();
211     }
212
213
214
215 }

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.