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() {
return identifier;
}
- public Iterable<DataChangeListenerRegistration<?>> getListeners() {
- return listeners;
+ /**
+ * Return the list of current listeners. Any caller wishing to use this method
+ * has to make sure the collection remains unchanged while it's executing. This
+ * means the caller has to synchronize externally both the registration and
+ * unregistration process.
+ *
+ * @return the list of current listeners
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public Collection<org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration<?>> getListeners() {
+ 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 synchronized <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);
+ LOG.debug("Listener {} registered", listener);
return listenerReg;
}
- private void removeListener(final DataChangeListenerRegistration<?> listener) {
+ private synchronized void removeListener(final DataChangeListenerRegistration<?> listener) {
listeners.remove(listener);
+ LOG.debug("Listener {} unregistered", listener);
removeThisIfUnused();
}
-
private void removeThisIfUnused() {
- if(parent != null && listeners.isEmpty() && children.isEmpty()) {
+ if (parent != null && listeners.isEmpty() && children.isEmpty()) {
parent.removeChildIfUnused(this);
}
}
}
private boolean areChildrenUnused() {
- for(ListenerRegistrationNode child : children.values()) {
- if(!child.isUnused()) {
+ for (ListenerRegistrationNode child : children.values()) {
+ if (!child.isUnused()) {
return false;
}
}
// 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;
}
node.removeListener(this);
node = null;
}
+
+ @Override
+ public InstanceIdentifier getPath() {
+ return path;
+ }
}
}