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%2FDataTreeChangeListenerProxy.java;fp=opendaylight%2Fmd-sal%2Fsal-distributed-datastore%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fdatastore%2FDataTreeChangeListenerProxy.java;h=124724b9c20c410760e43402b0f6958d5e7c9f9c;hp=0000000000000000000000000000000000000000;hb=66d39ecc3effd52c96c7a772a46612008e34fbc9;hpb=8eaba1eb027b02f8b36480721055dc99c6700e85 diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataTreeChangeListenerProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataTreeChangeListenerProxy.java new file mode 100644 index 0000000000..124724b9c2 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataTreeChangeListenerProxy.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +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.base.Preconditions; +import javax.annotation.concurrent.GuardedBy; +import org.opendaylight.controller.cluster.datastore.exceptions.LocalShardNotFoundException; +import org.opendaylight.controller.cluster.datastore.messages.CloseDataTreeChangeListenerRegistration; +import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeChangeListener; +import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeChangeListenerReply; +import org.opendaylight.controller.cluster.datastore.utils.ActorContext; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener; +import org.opendaylight.yangtools.concepts.AbstractListenerRegistration; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import scala.concurrent.Future; + +/** + * Proxy class for holding required state to lazily instantiate a listener registration with an + * asynchronously-discovered actor. + * + * @param listener type + */ +final class DataTreeChangeListenerProxy extends AbstractListenerRegistration { + private static final Logger LOG = LoggerFactory.getLogger(DataTreeChangeListenerProxy.class); + private final ActorRef dataChangeListenerActor; + private final ActorContext actorContext; + + @GuardedBy("this") + private ActorSelection listenerRegistrationActor; + + public DataTreeChangeListenerProxy(final ActorContext actorContext, final T listener) { + super(listener); + this.actorContext = Preconditions.checkNotNull(actorContext); + this.dataChangeListenerActor = actorContext.getActorSystem().actorOf( + DataTreeChangeListenerActor.props(getInstance()).withDispatcher(actorContext.getNotificationDispatcherPath())); + } + + @Override + protected synchronized void removeRegistration() { + if (listenerRegistrationActor != null) { + listenerRegistrationActor.tell(CloseDataTreeChangeListenerRegistration.getInstance(), ActorRef.noSender()); + listenerRegistrationActor = null; + } + + dataChangeListenerActor.tell(PoisonPill.getInstance(), ActorRef.noSender()); + } + + void init(final String shardName, final YangInstanceIdentifier treeId) { + 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 {} - DataTreeChangeListener {} at path {} " + + "cannot be registered", shardName, getInstance(), treeId); + } else if (failure != null) { + LOG.error("Failed to find local shard {} - DataTreeChangeListener {} at path {} " + + "cannot be registered: {}", shardName, getInstance(), treeId, failure); + } else { + doRegistration(shard, treeId); + } + } + }, actorContext.getClientDispatcher()); + } + + private void setListenerRegistrationActor(final ActorSelection actor) { + if (actor == null) { + LOG.debug("Ignoring null actor on {}", this); + return; + } + + synchronized (this) { + if (!isClosed()) { + this.listenerRegistrationActor = actor; + return; + } + } + + // This registration has already been closed, notify the actor + actor.tell(CloseDataTreeChangeListenerRegistration.getInstance(), null); + } + + private void doRegistration(final ActorRef shard, final YangInstanceIdentifier path) { + + Future future = actorContext.executeOperationAsync(shard, + new RegisterDataTreeChangeListener(path, dataChangeListenerActor), + 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 DataTreeChangeListener {} at path {}", + getInstance(), path.toString(), failure); + } else { + RegisterDataTreeChangeListenerReply reply = (RegisterDataTreeChangeListenerReply) result; + setListenerRegistrationActor(actorContext.actorSelection( + reply.getListenerRegistrationPath().path())); + } + } + }, actorContext.getClientDispatcher()); + } +}