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 / ListenerRegistrationNode.java
1 package org.opendaylight.controller.md.sal.dom.store.impl.tree;
2
3 import java.util.HashMap;
4 import java.util.Map;
5 import java.util.concurrent.ConcurrentSkipListSet;
6
7 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
8 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
9 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
10 import org.opendaylight.yangtools.concepts.Identifiable;
11 import org.opendaylight.yangtools.concepts.ListenerRegistration;
12 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
13 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
14 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
15
16 import com.google.common.base.Optional;
17
18 public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrationNode>,Identifiable<PathArgument> {
19
20     private final ListenerRegistrationNode parent;
21     private final Map<PathArgument, ListenerRegistrationNode> children;
22     private final PathArgument identifier;
23     private final ConcurrentSkipListSet<DataChangeListenerRegistration<?>> listeners;
24
25     private ListenerRegistrationNode(final PathArgument identifier) {
26         this(null,identifier);
27     }
28
29     private ListenerRegistrationNode(final ListenerRegistrationNode parent,final PathArgument identifier) {
30         this.parent = parent;
31         this.identifier = identifier;
32         children = new HashMap<>();
33         listeners = new ConcurrentSkipListSet<>();
34     }
35
36     public final static ListenerRegistrationNode createRoot() {
37         return new ListenerRegistrationNode(null);
38     }
39
40     @Override
41     public PathArgument getIdentifier() {
42         return identifier;
43     }
44
45     public Iterable<DataChangeListenerRegistration<?>> getListeners() {
46         return listeners;
47     }
48
49     @Override
50     public synchronized Optional<ListenerRegistrationNode> getChild(final PathArgument child) {
51         ListenerRegistrationNode potential = (children.get(child));
52         if(potential == null) {
53             potential = new ListenerRegistrationNode(this, child);
54             children.put(child, potential);
55         }
56         return Optional.of(potential);
57     }
58
59     public <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> ListenerRegistration<L> registerDataChangeListener(
60             final L listener, final DataChangeScope scope) {
61         DataChangeListenerRegistration<L> listenerReg = new DataChangeListenerRegistration<L>(listener, scope,this);
62         listeners.add(listenerReg);
63         return listenerReg;
64     }
65
66     private void removeListener(final DataChangeListenerRegistration<?> listener) {
67         listeners.remove(listener);
68         removeThisIfUnused();
69     }
70
71
72     private void removeThisIfUnused() {
73         if(parent != null && listeners.isEmpty() && children.isEmpty()) {
74             parent.removeChildIfUnused(this);
75         }
76     }
77
78     public boolean isUnused() {
79         return (listeners.isEmpty() && children.isEmpty()) || areChildrenUnused();
80     }
81
82     private boolean areChildrenUnused() {
83         for(ListenerRegistrationNode child :  children.values()) {
84             if(!child.isUnused()) {
85                 return false;
86             }
87         }
88         return true;
89     }
90
91     private void removeChildIfUnused(final ListenerRegistrationNode listenerRegistrationNode) {
92         // FIXME Remove unnecessary
93     }
94
95
96
97
98     public static class DataChangeListenerRegistration<T extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> extends AbstractObjectRegistration<T>
99             implements ListenerRegistration<T> {
100
101         private final DataChangeScope scope;
102         private ListenerRegistrationNode node;
103
104         public DataChangeListenerRegistration(final T listener, final DataChangeScope scope, final ListenerRegistrationNode node) {
105             super(listener);
106
107             this.scope = scope;
108             this.node = node;
109         }
110
111         protected DataChangeScope getScope() {
112             return scope;
113         }
114
115         @Override
116         protected void removeRegistration() {
117             node.removeListener(this);
118             node = null;
119         }
120     }
121 }