X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-distributed-datastore%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fdatastore%2FDataChangeListenerRegistrationProxy.java;h=681132e660d9608f3dea75e58eb4a9f3809f8dd6;hp=89cc9695251d18b2efc747b0de2b2882431a8de5;hb=707e2aa73c7314180472539ed4137950d33f5776;hpb=e2df8aa67238c153f1038eb45f7799442861985b 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 89cc969525..681132e660 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 @@ -8,12 +8,25 @@ package org.opendaylight.controller.cluster.datastore; +import akka.actor.ActorRef; import akka.actor.ActorSelection; +import akka.actor.PoisonPill; +import akka.dispatch.OnComplete; +import com.google.common.annotations.VisibleForTesting; +import org.opendaylight.controller.cluster.datastore.exceptions.LocalShardNotFoundException; import org.opendaylight.controller.cluster.datastore.messages.CloseDataChangeListenerRegistration; +import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener; +import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply; +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.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +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 @@ -22,25 +35,123 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; * The ListenerRegistrationProxy talks to a remote ListenerRegistration actor. *

*/ +@SuppressWarnings("rawtypes") public class DataChangeListenerRegistrationProxy implements ListenerRegistration { - private final ActorSelection listenerRegistrationActor; - private final AsyncDataChangeListener listener; - - public >> - DataChangeListenerRegistrationProxy( - ActorSelection listenerRegistrationActor, - L listener) { - this.listenerRegistrationActor = listenerRegistrationActor; + + private static final Logger LOG = LoggerFactory.getLogger(DataChangeListenerRegistrationProxy.class); + + private volatile ActorSelection listenerRegistrationActor; + private final AsyncDataChangeListener> listener; + private ActorRef dataChangeListenerActor; + private final String shardName; + private final ActorContext actorContext; + private boolean closed = false; + + public >> + DataChangeListenerRegistrationProxy ( + String shardName, ActorContext actorContext, L listener) { + this.shardName = shardName; + this.actorContext = actorContext; this.listener = listener; } + @VisibleForTesting + ActorSelection getListenerRegistrationActor() { + return listenerRegistrationActor; + } + + @VisibleForTesting + ActorRef getDataChangeListenerActor() { + return dataChangeListenerActor; + } + @Override public Object getInstance() { return listener; } + private void setListenerRegistrationActor(ActorSelection listenerRegistrationActor) { + if(listenerRegistrationActor == null) { + return; + } + + boolean sendCloseMessage = false; + synchronized(this) { + if(closed) { + sendCloseMessage = true; + } else { + this.listenerRegistrationActor = listenerRegistrationActor; + } + } + + if(sendCloseMessage) { + listenerRegistrationActor.tell(new + CloseDataChangeListenerRegistration().toSerializable(), null); + } + } + + public void init(final YangInstanceIdentifier path, final AsyncDataBroker.DataChangeScope scope) { + + dataChangeListenerActor = actorContext.getActorSystem().actorOf( + DataChangeListener.props(listener).withDispatcher(actorContext.getNotificationDispatcherPath())); + + Future findFuture = actorContext.findLocalShardAsync(shardName); + findFuture.onComplete(new OnComplete() { + @Override + public void onComplete(Throwable failure, 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()); + } + + private void doRegistration(ActorRef shard, final YangInstanceIdentifier path, + DataChangeScope scope) { + + Future future = actorContext.executeOperationAsync(shard, + new RegisterChangeListener(path, dataChangeListenerActor.path(), scope), + actorContext.getDatastoreContext().getShardInitializationTimeout()); + + future.onComplete(new OnComplete(){ + @Override + public void onComplete(Throwable failure, Object result) { + if(failure != null) { + LOG.error("Failed to register DataChangeListener {} at path {}", + listener, path.toString(), failure); + } else { + RegisterChangeListenerReply reply = (RegisterChangeListenerReply) result; + setListenerRegistrationActor(actorContext.actorSelection( + reply.getListenerRegistrationPath())); + } + } + }, actorContext.getClientDispatcher()); + } + @Override public void close() { - listenerRegistrationActor.tell(new CloseDataChangeListenerRegistration(), null); + + boolean sendCloseMessage; + synchronized(this) { + sendCloseMessage = !closed && listenerRegistrationActor != null; + closed = true; + } + + if(sendCloseMessage) { + listenerRegistrationActor.tell(new CloseDataChangeListenerRegistration().toSerializable(), + ActorRef.noSender()); + listenerRegistrationActor = null; + } + + if(dataChangeListenerActor != null) { + dataChangeListenerActor.tell(PoisonPill.getInstance(), ActorRef.noSender()); + dataChangeListenerActor = null; + } } }