1 package org.opendaylight.controller.md.sal.dom.store.impl.tree;
3 import java.util.Collection;
4 import java.util.HashMap;
5 import java.util.HashSet;
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;
18 import com.google.common.base.Optional;
20 public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrationNode>, Identifiable<PathArgument> {
22 private static final Logger LOG = LoggerFactory.getLogger(ListenerRegistrationNode.class);
24 private final ListenerRegistrationNode parent;
25 private final Map<PathArgument, ListenerRegistrationNode> children;
26 private final PathArgument identifier;
27 private final HashSet<DataChangeListenerRegistration<?>> listeners;
29 private ListenerRegistrationNode(final PathArgument identifier) {
30 this(null, identifier);
33 private ListenerRegistrationNode(final ListenerRegistrationNode parent, final PathArgument identifier) {
35 this.identifier = identifier;
36 children = new HashMap<>();
37 listeners = new HashSet<>();
40 public final static ListenerRegistrationNode createRoot() {
41 return new ListenerRegistrationNode(null);
45 public PathArgument getIdentifier() {
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;
56 public synchronized Optional<ListenerRegistrationNode> getChild(final PathArgument child) {
57 return Optional.fromNullable(children.get(child));
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);
71 * Registers listener on this node.
73 * @param path Full path on which listener is registered.
74 * @param listener Listener
75 * @param scope Scope of triggering event.
78 public <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> DataChangeListenerRegistration<L> registerDataChangeListener(final InstanceIdentifier path,
79 final L listener, final DataChangeScope scope) {
81 DataChangeListenerRegistration<L> listenerReg = new DataChangeListenerRegistration<L>(path,listener, scope, this);
82 listeners.add(listenerReg);
86 private void removeListener(final DataChangeListenerRegistration<?> listener) {
87 listeners.remove(listener);
91 private void removeThisIfUnused() {
92 if (parent != null && listeners.isEmpty() && children.isEmpty()) {
93 parent.removeChildIfUnused(this);
97 public boolean isUnused() {
98 return (listeners.isEmpty() && children.isEmpty()) || areChildrenUnused();
101 private boolean areChildrenUnused() {
102 for (ListenerRegistrationNode child : children.values()) {
103 if (!child.isUnused()) {
110 private void removeChildIfUnused(final ListenerRegistrationNode listenerRegistrationNode) {
111 // FIXME Remove unnecessary
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> {
118 private final DataChangeScope scope;
119 private ListenerRegistrationNode node;
120 private final InstanceIdentifier path;
122 public DataChangeListenerRegistration(final InstanceIdentifier path,final T listener, final DataChangeScope scope,
123 final ListenerRegistrationNode node) {
131 public DataChangeScope getScope() {
136 protected void removeRegistration() {
137 node.removeListener(this);
142 public InstanceIdentifier getPath() {