e48438d6fa63aa1888fe8ab0df580ca7881d5650
[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.Collection;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Map;
7
8 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
9 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
10 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
11 import org.opendaylight.yangtools.concepts.Identifiable;
12 import org.opendaylight.yangtools.concepts.ListenerRegistration;
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 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 import com.google.common.base.Optional;
20
21 public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrationNode>, Identifiable<PathArgument> {
22
23     private final Logger LOG = LoggerFactory.getLogger(ListenerRegistrationNode.class);
24
25     private final ListenerRegistrationNode parent;
26     private final Map<PathArgument, ListenerRegistrationNode> children;
27     private final PathArgument identifier;
28     private final HashSet<DataChangeListenerRegistration<?>> listeners;
29
30     private ListenerRegistrationNode(final PathArgument identifier) {
31         this(null, identifier);
32     }
33
34     private ListenerRegistrationNode(final ListenerRegistrationNode parent, final PathArgument identifier) {
35         this.parent = parent;
36         this.identifier = identifier;
37         children = new HashMap<>();
38         listeners = new HashSet<>();
39     }
40
41     public final static ListenerRegistrationNode createRoot() {
42         return new ListenerRegistrationNode(null);
43     }
44
45     @Override
46     public PathArgument getIdentifier() {
47         return identifier;
48     }
49
50     @SuppressWarnings({ "rawtypes", "unchecked" })
51     public Collection<org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration<?>> getListeners() {
52         return (Collection) listeners;
53     }
54
55     @Override
56     public synchronized Optional<ListenerRegistrationNode> getChild(final PathArgument child) {
57         return Optional.fromNullable(children.get(child));
58     }
59
60     public synchronized ListenerRegistrationNode ensureChild(final PathArgument child) {
61         ListenerRegistrationNode potential = (children.get(child));
62         if (potential == null) {
63             potential = new ListenerRegistrationNode(this, child);
64             children.put(child, potential);
65         }
66         return potential;
67     }
68
69     /**
70      *
71      * Registers listener on this node.
72      *
73      * @param path Full path on which listener is registered.
74      * @param listener Listener
75      * @param scope Scope of triggering event.
76      * @return
77      */
78     public <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> ListenerRegistration<L> registerDataChangeListener(final InstanceIdentifier path,
79             final L listener, final DataChangeScope scope) {
80
81         DataChangeListenerRegistration<L> listenerReg = new DataChangeListenerRegistration<L>(path,listener, scope, this);
82         listeners.add(listenerReg);
83         return listenerReg;
84     }
85
86     private void removeListener(final DataChangeListenerRegistration<?> listener) {
87         listeners.remove(listener);
88         removeThisIfUnused();
89     }
90
91     private void removeThisIfUnused() {
92         if (parent != null && listeners.isEmpty() && children.isEmpty()) {
93             parent.removeChildIfUnused(this);
94         }
95     }
96
97     public boolean isUnused() {
98         return (listeners.isEmpty() && children.isEmpty()) || areChildrenUnused();
99     }
100
101     private boolean areChildrenUnused() {
102         for (ListenerRegistrationNode child : children.values()) {
103             if (!child.isUnused()) {
104                 return false;
105             }
106         }
107         return true;
108     }
109
110     private void removeChildIfUnused(final ListenerRegistrationNode listenerRegistrationNode) {
111         // FIXME Remove unnecessary
112     }
113
114     public static class DataChangeListenerRegistration<T extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>>
115             extends AbstractObjectRegistration<T> implements
116             org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration<T> {
117
118         private final DataChangeScope scope;
119         private ListenerRegistrationNode node;
120         private final InstanceIdentifier path;
121
122         public DataChangeListenerRegistration(final InstanceIdentifier path,final T listener, final DataChangeScope scope,
123                 final ListenerRegistrationNode node) {
124             super(listener);
125             this.path = path;
126             this.scope = scope;
127             this.node = node;
128         }
129
130         @Override
131         public DataChangeScope getScope() {
132             return scope;
133         }
134
135         @Override
136         protected void removeRegistration() {
137             node.removeListener(this);
138             node = null;
139         }
140
141         @Override
142         public InstanceIdentifier getPath() {
143             return path;
144         }
145     }
146 }