BUG-509: make sure datastore commits are visible
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / md / sal / dom / store / impl / tree / ListenerRegistrationNode.java
index d6d1ca309fc7eaa5b55ed83b52a07cb7f60c6506..2528d383b95a0c9f6534ad0f01627f56dbc26c5c 100644 (file)
@@ -1,36 +1,40 @@
 package org.opendaylight.controller.md.sal.dom.store.impl.tree;
 
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
-import java.util.concurrent.ConcurrentSkipListSet;
 
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
 import org.opendaylight.yangtools.concepts.Identifiable;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
 
-public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrationNode>,Identifiable<PathArgument> {
+public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrationNode>, Identifiable<PathArgument> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ListenerRegistrationNode.class);
 
     private final ListenerRegistrationNode parent;
     private final Map<PathArgument, ListenerRegistrationNode> children;
     private final PathArgument identifier;
-    private final ConcurrentSkipListSet<DataChangeListenerRegistration<?>> listeners;
+    private final HashSet<DataChangeListenerRegistration<?>> listeners;
 
     private ListenerRegistrationNode(final PathArgument identifier) {
-        this(null,identifier);
+        this(null, identifier);
     }
 
-    private ListenerRegistrationNode(final ListenerRegistrationNode parent,final PathArgument identifier) {
+    private ListenerRegistrationNode(final ListenerRegistrationNode parent, final PathArgument identifier) {
         this.parent = parent;
         this.identifier = identifier;
         children = new HashMap<>();
-        listeners = new ConcurrentSkipListSet<>();
+        listeners = new HashSet<>();
     }
 
     public final static ListenerRegistrationNode createRoot() {
@@ -42,23 +46,39 @@ public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrat
         return identifier;
     }
 
-    public Iterable<DataChangeListenerRegistration<?>> getListeners() {
-        return listeners;
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public Collection<org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration<?>> getListeners() {
+        // FIXME: this is not thread-safe and races with listener (un)registration!
+        return (Collection) listeners;
     }
 
     @Override
     public synchronized Optional<ListenerRegistrationNode> getChild(final PathArgument child) {
+        return Optional.fromNullable(children.get(child));
+    }
+
+    public synchronized ListenerRegistrationNode ensureChild(final PathArgument child) {
         ListenerRegistrationNode potential = (children.get(child));
-        if(potential == null) {
+        if (potential == null) {
             potential = new ListenerRegistrationNode(this, child);
             children.put(child, potential);
         }
-        return Optional.of(potential);
+        return potential;
     }
 
-    public <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> ListenerRegistration<L> registerDataChangeListener(
+    /**
+     *
+     * Registers listener on this node.
+     *
+     * @param path Full path on which listener is registered.
+     * @param listener Listener
+     * @param scope Scope of triggering event.
+     * @return
+     */
+    public <L extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> DataChangeListenerRegistration<L> registerDataChangeListener(final InstanceIdentifier path,
             final L listener, final DataChangeScope scope) {
-        DataChangeListenerRegistration<L> listenerReg = new DataChangeListenerRegistration<L>(listener, scope,this);
+
+        DataChangeListenerRegistration<L> listenerReg = new DataChangeListenerRegistration<L>(path,listener, scope, this);
         listeners.add(listenerReg);
         return listenerReg;
     }
@@ -68,9 +88,8 @@ public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrat
         removeThisIfUnused();
     }
 
-
     private void removeThisIfUnused() {
-        if(parent != null && listeners.isEmpty() && children.isEmpty()) {
+        if (parent != null && listeners.isEmpty() && children.isEmpty()) {
             parent.removeChildIfUnused(this);
         }
     }
@@ -80,8 +99,8 @@ public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrat
     }
 
     private boolean areChildrenUnused() {
-        for(ListenerRegistrationNode child :  children.values()) {
-            if(!child.isUnused()) {
+        for (ListenerRegistrationNode child : children.values()) {
+            if (!child.isUnused()) {
                 return false;
             }
         }
@@ -92,23 +111,24 @@ public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrat
         // FIXME Remove unnecessary
     }
 
-
-
-
-    public static class DataChangeListenerRegistration<T extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> extends AbstractObjectRegistration<T>
-            implements ListenerRegistration<T> {
+    public static class DataChangeListenerRegistration<T extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>>
+            extends AbstractObjectRegistration<T> implements
+            org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration<T> {
 
         private final DataChangeScope scope;
         private ListenerRegistrationNode node;
+        private final InstanceIdentifier path;
 
-        public DataChangeListenerRegistration(final T listener, final DataChangeScope scope, final ListenerRegistrationNode node) {
+        public DataChangeListenerRegistration(final InstanceIdentifier path,final T listener, final DataChangeScope scope,
+                final ListenerRegistrationNode node) {
             super(listener);
-
+            this.path = path;
             this.scope = scope;
             this.node = node;
         }
 
-        protected DataChangeScope getScope() {
+        @Override
+        public DataChangeScope getScope() {
             return scope;
         }
 
@@ -117,5 +137,10 @@ public class ListenerRegistrationNode implements StoreTreeNode<ListenerRegistrat
             node.removeListener(this);
             node = null;
         }
+
+        @Override
+        public InstanceIdentifier getPath() {
+            return path;
+        }
     }
 }