X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-distributed-datastore%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fdatastore%2FDataChangeListenerRegistrationProxy.java;h=33cf8e9c1d292ca46f47cfb3efd9497ed38a63cc;hb=f41c5e6e6f6e10b36b1e4b1992877e38e718c8fb;hp=acf630e2e95598e71fdbd786da628f3524a29408;hpb=5834673a28941e470173b5215f56cebdf0cfa2f0;p=controller.git diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationProxy.java index acf630e2e9..33cf8e9c1d 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListenerRegistrationProxy.java @@ -11,38 +11,60 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; import akka.actor.ActorSelection; import akka.actor.PoisonPill; -import org.opendaylight.controller.cluster.datastore.messages.CloseDataChangeListenerRegistration; +import akka.dispatch.OnComplete; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import org.opendaylight.controller.cluster.datastore.exceptions.LocalShardNotFoundException; +import org.opendaylight.controller.cluster.datastore.messages.CloseDataTreeNotificationListenerRegistration; +import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener; +import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeNotificationListenerReply; +import org.opendaylight.controller.cluster.datastore.utils.ActorContext; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.ClusteredDOMDataChangeListener; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import scala.concurrent.Future; /** - * ListenerRegistrationProxy acts as a proxy for a ListenerRegistration that was done on a remote shard + * ListenerRegistrationProxy acts as a proxy for a ListenerRegistration that was done on a remote shard. + * *

* Registering a DataChangeListener on the Data Store creates a new instance of the ListenerRegistrationProxy * The ListenerRegistrationProxy talks to a remote ListenerRegistration actor. - *

*/ +@SuppressWarnings("rawtypes") public class DataChangeListenerRegistrationProxy implements ListenerRegistration { + + private static final Logger LOG = LoggerFactory.getLogger(DataChangeListenerRegistrationProxy.class); + + private final AsyncDataChangeListener> listener; + private final String shardName; + private final ActorContext actorContext; + private ActorRef dataChangeListenerActor; private volatile ActorSelection listenerRegistrationActor; - private final AsyncDataChangeListener listener; - private final ActorRef dataChangeListenerActor; private boolean closed = false; public >> - DataChangeListenerRegistrationProxy( - ActorSelection listenerRegistrationActor, - L listener, ActorRef dataChangeListenerActor) { - this.listenerRegistrationActor = listenerRegistrationActor; - this.listener = listener; - this.dataChangeListenerActor = dataChangeListenerActor; + DataChangeListenerRegistrationProxy(final String shardName, final ActorContext actorContext, + final L listener) { + this.shardName = Preconditions.checkNotNull(shardName); + this.actorContext = Preconditions.checkNotNull(actorContext); + this.listener = Preconditions.checkNotNull(listener); } - public >> - DataChangeListenerRegistrationProxy( - L listener, ActorRef dataChangeListenerActor) { - this(null, listener, dataChangeListenerActor); + @VisibleForTesting + ActorSelection getListenerRegistrationActor() { + return listenerRegistrationActor; + } + + @VisibleForTesting + ActorRef getDataChangeListenerActor() { + return dataChangeListenerActor; } @Override @@ -50,40 +72,89 @@ public class DataChangeListenerRegistrationProxy implements ListenerRegistration return listener; } - public void setListenerRegistrationActor(ActorSelection listenerRegistrationActor) { + private void setListenerRegistrationActor(final ActorSelection listenerRegistrationActor) { + if (listenerRegistrationActor == null) { + return; + } + boolean sendCloseMessage = false; - synchronized(this) { - if(closed) { + synchronized (this) { + if (closed) { sendCloseMessage = true; } else { this.listenerRegistrationActor = listenerRegistrationActor; } } - if(sendCloseMessage) { - listenerRegistrationActor.tell(new - CloseDataChangeListenerRegistration().toSerializable(), null); + + if (sendCloseMessage) { + listenerRegistrationActor.tell(CloseDataTreeNotificationListenerRegistration.getInstance(), + ActorRef.noSender()); } + } + + public void init(final YangInstanceIdentifier path, final AsyncDataBroker.DataChangeScope scope) { + + dataChangeListenerActor = actorContext.getActorSystem().actorOf( + DataChangeListener.props(listener, path).withDispatcher(actorContext.getNotificationDispatcherPath())); - this.listenerRegistrationActor = listenerRegistrationActor; + Future findFuture = actorContext.findLocalShardAsync(shardName); + findFuture.onComplete(new OnComplete() { + @Override + public void onComplete(final Throwable failure, final ActorRef shard) { + if (failure instanceof LocalShardNotFoundException) { + LOG.debug("No local shard found for {} - DataChangeListener {} at path {} " + + "cannot be registered", shardName, listener, path); + } else if (failure != null) { + LOG.error("Failed to find local shard {} - DataChangeListener {} at path {} " + + "cannot be registered: {}", shardName, listener, path, failure); + } else { + doRegistration(shard, path, scope); + } + } + }, actorContext.getClientDispatcher()); } - public ActorSelection getListenerRegistrationActor() { - return listenerRegistrationActor; + private void doRegistration(final ActorRef shard, final YangInstanceIdentifier path, + final DataChangeScope scope) { + + Future future = actorContext.executeOperationAsync(shard, + new RegisterChangeListener(path, dataChangeListenerActor, scope, + listener instanceof ClusteredDOMDataChangeListener), + actorContext.getDatastoreContext().getShardInitializationTimeout()); + + future.onComplete(new OnComplete() { + @Override + public void onComplete(final Throwable failure, final Object result) { + if (failure != null) { + LOG.error("Failed to register DataChangeListener {} at path {}", + listener, path.toString(), failure); + } else { + RegisterDataTreeNotificationListenerReply reply = (RegisterDataTreeNotificationListenerReply)result; + setListenerRegistrationActor(actorContext.actorSelection( + reply.getListenerRegistrationPath())); + } + } + }, actorContext.getClientDispatcher()); } @Override public void close() { boolean sendCloseMessage; - synchronized(this) { + synchronized (this) { sendCloseMessage = !closed && listenerRegistrationActor != null; closed = true; } - if(sendCloseMessage) { - listenerRegistrationActor.tell(new - CloseDataChangeListenerRegistration().toSerializable(), null); + + if (sendCloseMessage) { + listenerRegistrationActor.tell(CloseDataTreeNotificationListenerRegistration.getInstance(), + ActorRef.noSender()); + listenerRegistrationActor = null; } - dataChangeListenerActor.tell(PoisonPill.getInstance(), null); + if (dataChangeListenerActor != null) { + dataChangeListenerActor.tell(PoisonPill.getInstance(), ActorRef.noSender()); + dataChangeListenerActor = null; + } } }