Merge "Add filtering capability to config.ini in order to reference logging bridge...
[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.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 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17
18 import com.google.common.base.Optional;
19
20 public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrationNode>, Identifiable<PathArgument> {
21
22     private static final Logger LOG = LoggerFactory.getLogger(ListenerRegistrationNode.class);
23
24     private final ListenerRegistrationNode parent;
25     private final Map<PathArgument, ListenerRegistrationNode> children;
26     private final PathArgument identifier;
27     private final HashSet<DataChangeListenerRegistration<?>> listeners;
28
29     private ListenerRegistrationNode(final PathArgument identifier) {
30         this(null, identifier);
31     }
32
33     private ListenerRegistrationNode(final ListenerRegistrationNode parent, final PathArgument identifier) {
34         this.parent = parent;
35         this.identifier = identifier;
36         children = new HashMap<>();
37         listeners = new HashSet<>();
38     }
39
40     public final static ListenerRegistrationNode createRoot() {
41         return new ListenerRegistrationNode(null);
42     }
43
44     @Override
45     public PathArgument getIdentifier() {
46         return identifier;
47     }
48
49     @SuppressWarnings({ "rawtypes", "unchecked" })
50     public Collection<org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration<?>> getListeners() {
51         // FIXME: this is not thread-safe and races with listener (un)registration!
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<?, ?>>> DataChangeListenerRegistration<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 }