Remove deprecated controller EOS APIs and impl
[controller.git] / opendaylight / md-sal / samples / clustering-test-app / provider / src / main / java / org / opendaylight / controller / clustering / it / provider / MdsalLowLevelTestProvider.java
index bea3bcd11f0c6f68c02c69cccc79c250bc2fc54c..ec3da0ef36958e8684470f9b7da3619fab4bbeb8 100644 (file)
@@ -14,17 +14,20 @@ import akka.actor.ActorRef;
 import akka.actor.ActorSystem;
 import akka.actor.PoisonPill;
 import akka.actor.Props;
+import akka.dispatch.OnComplete;
+import akka.pattern.Patterns;
 import com.google.common.base.Optional;
+import com.google.common.base.Strings;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.SettableFuture;
-import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import org.opendaylight.controller.cluster.ActorSystemProvider;
 import org.opendaylight.controller.cluster.databroker.actors.dds.ClientLocalHistory;
 import org.opendaylight.controller.cluster.databroker.actors.dds.ClientTransaction;
@@ -33,6 +36,7 @@ import org.opendaylight.controller.cluster.databroker.actors.dds.SimpleDataStore
 import org.opendaylight.controller.cluster.datastore.DistributedDataStoreInterface;
 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
 import org.opendaylight.controller.cluster.datastore.utils.ClusterUtils;
+import org.opendaylight.controller.cluster.raft.client.messages.Shutdown;
 import org.opendaylight.controller.cluster.sharding.DistributedShardFactory;
 import org.opendaylight.controller.clustering.it.provider.impl.FlappingSingletonService;
 import org.opendaylight.controller.clustering.it.provider.impl.GetConstantService;
@@ -81,6 +85,8 @@ import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.l
 import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.RegisterSingletonConstantInput;
 import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.RemovePrefixShardInput;
 import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.RemoveShardReplicaInput;
+import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.ShutdownPrefixShardReplicaInput;
+import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.ShutdownShardReplicaInput;
 import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.StartPublishNotificationsInput;
 import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.SubscribeYnlInput;
 import org.opendaylight.yang.gen.v1.tag.opendaylight.org._2017.controller.yang.lowlevel.control.rev170215.UnregisterBoundConstantInput;
@@ -104,6 +110,7 @@ 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.duration.FiniteDuration;
 
 public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService {
 
@@ -128,17 +135,17 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
     private final DOMDataTreeChangeService domDataTreeChangeService;
     private final ActorSystem actorSystem;
 
-    private Map<InstanceIdentifier<?>, DOMRpcImplementationRegistration<RoutedGetConstantService>> routedRegistrations =
-            new HashMap<>();
+    private final Map<InstanceIdentifier<?>, DOMRpcImplementationRegistration<RoutedGetConstantService>>
+            routedRegistrations = new HashMap<>();
 
-    private Map<String, ListenerRegistration<YnlListener>> ynlRegistrations = new HashMap<>();
+    private final Map<String, ListenerRegistration<YnlListener>> ynlRegistrations = new HashMap<>();
 
     private DOMRpcImplementationRegistration<GetConstantService> globalGetConstantRegistration = null;
     private ClusterSingletonServiceRegistration getSingletonConstantRegistration;
     private FlappingSingletonService flappingSingletonService;
     private ListenerRegistration<DOMDataTreeChangeListener> dtclReg;
     private IdIntsListener idIntsListener;
-    private Map<String, PublishNotificationsTask> publishNotificationsTasks = new HashMap<>();
+    private final Map<String, PublishNotificationsTask> publishNotificationsTasks = new HashMap<>();
     private ListenerRegistration<IdIntsDOMDataTreeLIstener> ddtlReg;
     private IdIntsDOMDataTreeLIstener idIntsDdtl;
 
@@ -181,13 +188,14 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
     }
 
     @Override
+    @SuppressWarnings("checkstyle:IllegalCatch")
     public Future<RpcResult<Void>> unregisterSingletonConstant() {
         LOG.debug("unregister-singleton-constant");
 
         if (getSingletonConstantRegistration == null) {
             LOG.debug("No get-singleton-constant registration present.");
-            final RpcError rpcError = RpcResultBuilder
-                    .newError(ErrorType.APPLICATION, "missing-registration", "No get-singleton-constant rpc registration present.");
+            final RpcError rpcError = RpcResultBuilder.newError(ErrorType.APPLICATION, "missing-registration",
+                    "No get-singleton-constant rpc registration present.");
             final RpcResult<Void> result = RpcResultBuilder.<Void>failed().withRpcError(rpcError).build();
             return Futures.immediateFuture(result);
         }
@@ -197,10 +205,10 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
             getSingletonConstantRegistration = null;
 
             return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
-        } catch (final Exception e) {
+        } catch (Exception e) {
             LOG.debug("There was a problem closing the singleton constant service", e);
-            final RpcError rpcError = RpcResultBuilder
-                    .newError(ErrorType.APPLICATION, "error-closing", "There was a problem closing get-singleton-constant");
+            final RpcError rpcError = RpcResultBuilder.newError(ErrorType.APPLICATION, "error-closing",
+                    "There was a problem closing get-singleton-constant");
             final RpcResult<Void> result = RpcResultBuilder.<Void>failed().withRpcError(rpcError).build();
             return Futures.immediateFuture(result);
         }
@@ -243,13 +251,7 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
     @Override
     public Future<RpcResult<WriteTransactionsOutput>> writeTransactions(final WriteTransactionsInput input) {
         LOG.debug("write-transactions, input: {}", input);
-
-        final WriteTransactionsHandler writeTransactionsHandler = new WriteTransactionsHandler(domDataBroker, input);
-
-        final SettableFuture<RpcResult<WriteTransactionsOutput>> settableFuture = SettableFuture.create();
-        writeTransactionsHandler.start(settableFuture);
-
-        return settableFuture;
+        return WriteTransactionsHandler.start(domDataBroker, input);
     }
 
     @Override
@@ -258,7 +260,7 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
     }
 
     @Override
-    public Future<RpcResult<Void>> removeShardReplica(RemoveShardReplicaInput input) {
+    public Future<RpcResult<Void>> removeShardReplica(final RemoveShardReplicaInput input) {
         return null;
     }
 
@@ -297,18 +299,18 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
     public Future<RpcResult<Void>> unregisterBoundConstant(final UnregisterBoundConstantInput input) {
         LOG.debug("unregister-bound-constant, {}", input);
 
-        final DOMRpcImplementationRegistration<RoutedGetConstantService> registration =
+        final DOMRpcImplementationRegistration<RoutedGetConstantService> rpcRegistration =
                 routedRegistrations.remove(input.getContext());
 
-        if (registration == null) {
+        if (rpcRegistration == null) {
             LOG.debug("No get-contexted-constant registration for context: {}", input.getContext());
-            final RpcError rpcError = RpcResultBuilder
-                    .newError(ErrorType.APPLICATION, "missing-registration", "No get-constant rpc registration present.");
+            final RpcError rpcError = RpcResultBuilder.newError(ErrorType.APPLICATION, "missing-registration",
+                    "No get-constant rpc registration present.");
             final RpcResult<Void> result = RpcResultBuilder.<Void>failed().withRpcError(rpcError).build();
             return Futures.immediateFuture(result);
         }
 
-        registration.close();
+        rpcRegistration.close();
         return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
     }
 
@@ -330,7 +332,7 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
     }
 
     @Override
-    public Future<RpcResult<Void>> registerDefaultConstant(RegisterDefaultConstantInput input) {
+    public Future<RpcResult<Void>> registerDefaultConstant(final RegisterDefaultConstantInput input) {
         return null;
     }
 
@@ -338,8 +340,8 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
     public Future<RpcResult<Void>> unregisterConstant() {
 
         if (globalGetConstantRegistration == null) {
-            final RpcError rpcError = RpcResultBuilder
-                    .newError(ErrorType.APPLICATION, "missing-registration", "No get-constant rpc registration present.");
+            final RpcError rpcError = RpcResultBuilder.newError(ErrorType.APPLICATION, "missing-registration",
+                    "No get-constant rpc registration present.");
             final RpcResult<Void> result = RpcResultBuilder.<Void>failed().withRpcError(rpcError).build();
             return Futures.immediateFuture(result);
         }
@@ -355,8 +357,8 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
         LOG.debug("unregister-flapping-singleton received.");
 
         if (flappingSingletonService == null) {
-            final RpcError rpcError = RpcResultBuilder
-                    .newError(ErrorType.APPLICATION, "missing-registration", "No flapping-singleton registration present.");
+            final RpcError rpcError = RpcResultBuilder.newError(ErrorType.APPLICATION, "missing-registration",
+                    "No flapping-singleton registration present.");
             final RpcResult<UnregisterFlappingSingletonOutput> result =
                     RpcResultBuilder.<UnregisterFlappingSingletonOutput>failed().withRpcError(rpcError).build();
             return Futures.immediateFuture(result);
@@ -372,7 +374,7 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
     }
 
     @Override
-    public Future<RpcResult<Void>> addShardReplica(AddShardReplicaInput input) {
+    public Future<RpcResult<Void>> addShardReplica(final AddShardReplicaInput input) {
         return null;
     }
 
@@ -388,11 +390,10 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
         idIntsDdtl = new IdIntsDOMDataTreeLIstener();
 
         try {
-            ddtlReg =
-                    domDataTreeService.registerListener(idIntsDdtl,
-                            Collections.singleton(new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION,
-                                    ProduceTransactionsHandler.ID_INT_YID))
-                            , true, Collections.emptyList());
+            ddtlReg = domDataTreeService.registerListener(idIntsDdtl,
+                    Collections.singleton(new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION,
+                            ProduceTransactionsHandler.ID_INT_YID)),
+                    true, Collections.emptyList());
         } catch (DOMDataTreeLoopException e) {
             LOG.error("Failed to register DOMDataTreeListener.", e);
 
@@ -423,11 +424,11 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
             return Futures.immediateFuture(RpcResultBuilder.<Void>failed().withRpcError(error).build());
         }
 
-        final DOMRpcImplementationRegistration<RoutedGetConstantService> registration =
+        final DOMRpcImplementationRegistration<RoutedGetConstantService> rpcRegistration =
                 RoutedGetConstantService.registerNew(bindingNormalizedNodeSerializer, domRpcService,
                         input.getConstant(), input.getContext());
 
-        routedRegistrations.put(input.getContext(), registration);
+        routedRegistrations.put(input.getContext(), rpcRegistration);
         return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
     }
 
@@ -437,7 +438,7 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
 
         if (flappingSingletonService != null) {
             final RpcError error = RpcResultBuilder.newError(
-                    ErrorType.RPC, "Registration present.", "flappin-singleton already registered");
+                    ErrorType.RPC, "Registration present.", "flapping-singleton already registered");
             return Futures.immediateFuture(RpcResultBuilder.<Void>failed().withRpcError(error).build());
         }
 
@@ -453,18 +454,32 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
         if (idIntsListener == null || dtclReg == null) {
             final RpcError error = RpcResultBuilder.newError(
                     ErrorType.RPC, "Dtcl missing.", "No DataTreeChangeListener registered.");
-            return Futures.immediateFuture(RpcResultBuilder.<UnsubscribeDtclOutput>failed().withRpcError(error).build());
+            return Futures.immediateFuture(RpcResultBuilder.<UnsubscribeDtclOutput>failed()
+                    .withRpcError(error).build());
         }
 
-        final DOMDataReadOnlyTransaction rTx = domDataBroker.newReadOnlyTransaction();
         try {
-            if (dtclReg != null) {
-                dtclReg.close();
-                dtclReg = null;
-            }
+            idIntsListener.tryFinishProcessing().get(120, TimeUnit.SECONDS);
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            final RpcError error = RpcResultBuilder.newError(ErrorType.RPC, "resource-denied-transport",
+                    "Unable to finish notification processing in 120 seconds.", "clustering-it", "clustering-it", e);
+            return Futures.immediateFuture(RpcResultBuilder.<UnsubscribeDtclOutput>failed()
+                    .withRpcError(error).build());
+        }
 
+        dtclReg.close();
+        dtclReg = null;
 
+        if (!idIntsListener.hasTriggered()) {
+            final RpcError error = RpcResultBuilder.newError(
+                    ErrorType.APPLICATION, "No notification received.", "id-ints listener has not received"
+                            + "any notifications.");
+            return Futures.immediateFuture(RpcResultBuilder.<UnsubscribeDtclOutput>failed()
+                    .withRpcError(error).build());
+        }
 
+        final DOMDataReadOnlyTransaction rTx = domDataBroker.newReadOnlyTransaction();
+        try {
             final Optional<NormalizedNode<?, ?>> readResult =
                     rTx.read(CONTROLLER_CONFIG, WriteTransactionsHandler.ID_INT_YID).checkedGet();
 
@@ -505,17 +520,17 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
         LOG.debug("Received unsubscribe-ynl, input: {}", input);
 
         if (!ynlRegistrations.containsKey(input.getId())) {
-            final RpcError rpcError = RpcResultBuilder
-                    .newError(ErrorType.APPLICATION, "missing-registration", "No ynl listener with this id registered.");
+            final RpcError rpcError = RpcResultBuilder.newError(ErrorType.APPLICATION, "missing-registration",
+                    "No ynl listener with this id registered.");
             final RpcResult<UnsubscribeYnlOutput> result =
                     RpcResultBuilder.<UnsubscribeYnlOutput>failed().withRpcError(rpcError).build();
             return Futures.immediateFuture(result);
         }
 
-        final ListenerRegistration<YnlListener> registration = ynlRegistrations.remove(input.getId());
-        final UnsubscribeYnlOutput output = registration.getInstance().getOutput();
+        final ListenerRegistration<YnlListener> reg = ynlRegistrations.remove(input.getId());
+        final UnsubscribeYnlOutput output = reg.getInstance().getOutput();
 
-        registration.close();
+        reg.close();
 
         return Futures.immediateFuture(RpcResultBuilder.<UnsubscribeYnlOutput>success().withResult(output).build());
     }
@@ -535,10 +550,8 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
                 new CheckPublishNotificationsOutputBuilder().setActive(!task.isFinished());
 
         if (task.getLastError() != null) {
-            final StringWriter sw = new StringWriter();
-            final PrintWriter pw = new PrintWriter(sw);
-            task.getLastError().printStackTrace(pw);
-            checkPublishNotificationsOutputBuilder.setLastError(task.getLastError().toString() + sw.toString());
+            LOG.error("Last error for {}", task, task.getLastError());
+            checkPublishNotificationsOutputBuilder.setLastError(task.getLastError().toString());
         }
 
         final CheckPublishNotificationsOutput output =
@@ -550,14 +563,76 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
     @Override
     public Future<RpcResult<ProduceTransactionsOutput>> produceTransactions(final ProduceTransactionsInput input) {
         LOG.debug("producer-transactions, input: {}", input);
+        return ProduceTransactionsHandler.start(domDataTreeService, input);
+    }
+
+    @Override
+    public Future<RpcResult<Void>> shutdownShardReplica(final ShutdownShardReplicaInput input) {
+        LOG.debug("Received shutdown-shard-replica rpc, input: {}", input);
+
+        final String shardName = input.getShardName();
+        if (Strings.isNullOrEmpty(shardName)) {
+            final RpcError rpcError = RpcResultBuilder.newError(ErrorType.APPLICATION, "bad-element",
+                    "A valid shard name must be specified");
+            return Futures.immediateFuture(RpcResultBuilder.<Void>failed().withRpcError(rpcError).build());
+        }
+
+        return shutdownShardGracefully(shardName);
+    }
+
+    @Override
+    public Future<RpcResult<Void>> shutdownPrefixShardReplica(final ShutdownPrefixShardReplicaInput input) {
+        LOG.debug("Received shutdown-prefix-shard-replica rpc, input: {}", input);
 
-        final ProduceTransactionsHandler handler =
-                new ProduceTransactionsHandler(domDataTreeService, input);
+        final InstanceIdentifier<?> shardPrefix = input.getPrefix();
 
-        final SettableFuture<RpcResult<ProduceTransactionsOutput>> settableFuture = SettableFuture.create();
-        handler.start(settableFuture);
+        if (shardPrefix == null) {
+            final RpcError rpcError = RpcResultBuilder.newError(ErrorType.APPLICATION, "bad-element",
+                    "A valid shard prefix must be specified");
+            return Futures.immediateFuture(RpcResultBuilder.<Void>failed().withRpcError(rpcError).build());
+        }
+
+        final YangInstanceIdentifier shardPath = bindingNormalizedNodeSerializer.toYangInstanceIdentifier(shardPrefix);
+        final String cleanPrefixShardName = ClusterUtils.getCleanShardName(shardPath);
 
-        return settableFuture;
+        return shutdownShardGracefully(cleanPrefixShardName);
+    }
+
+    private SettableFuture<RpcResult<Void>> shutdownShardGracefully(final String shardName) {
+        final SettableFuture<RpcResult<Void>> rpcResult = SettableFuture.create();
+        final ActorContext context = configDataStore.getActorContext();
+
+        long timeoutInMS = Math.max(context.getDatastoreContext().getShardRaftConfig()
+                .getElectionTimeOutInterval().$times(3).toMillis(), 10000);
+        final FiniteDuration duration = FiniteDuration.apply(timeoutInMS, TimeUnit.MILLISECONDS);
+        final scala.concurrent.Promise<Boolean> shutdownShardAsk = akka.dispatch.Futures.promise();
+
+        context.findLocalShardAsync(shardName).onComplete(new OnComplete<ActorRef>() {
+            @Override
+            public void onComplete(final Throwable throwable, final ActorRef actorRef) throws Throwable {
+                if (throwable != null) {
+                    shutdownShardAsk.failure(throwable);
+                } else {
+                    shutdownShardAsk.completeWith(Patterns.gracefulStop(actorRef, duration, Shutdown.INSTANCE));
+                }
+            }
+        }, context.getClientDispatcher());
+
+        shutdownShardAsk.future().onComplete(new OnComplete<Boolean>() {
+            @Override
+            public void onComplete(final Throwable throwable, final Boolean gracefulStopResult) throws Throwable {
+                if (throwable != null) {
+                    final RpcResult<Void> failedResult = RpcResultBuilder.<Void>failed()
+                            .withError(ErrorType.APPLICATION, "Failed to gracefully shutdown shard", throwable).build();
+                    rpcResult.set(failedResult);
+                } else {
+                    // according to Patterns.gracefulStop API, we don't have to
+                    // check value of gracefulStopResult
+                    rpcResult.set(RpcResultBuilder.<Void>success().build());
+                }
+            }
+        }, context.getClientDispatcher());
+        return rpcResult;
     }
 
     @Override
@@ -587,18 +662,37 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
     }
 
     @Override
+    @SuppressWarnings("checkstyle:IllegalCatch")
     public Future<RpcResult<UnsubscribeDdtlOutput>> unsubscribeDdtl() {
         LOG.debug("Received unsubscribe-ddtl.");
 
         if (idIntsDdtl == null || ddtlReg == null) {
             final RpcError error = RpcResultBuilder.newError(
                     ErrorType.RPC, "Ddtl missing.", "No DOMDataTreeListener registered.");
-            return Futures.immediateFuture(RpcResultBuilder.<UnsubscribeDdtlOutput>failed().withRpcError(error).build());
+            return Futures.immediateFuture(RpcResultBuilder.<UnsubscribeDdtlOutput>failed()
+                    .withRpcError(error).build());
+        }
+
+        try {
+            idIntsDdtl.tryFinishProcessing().get(120, TimeUnit.SECONDS);
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            final RpcError error = RpcResultBuilder.newError(ErrorType.RPC, "resource-denied-transport",
+                    "Unable to finish notification processing in 120 seconds.", "clustering-it", "clustering-it", e);
+            return Futures.immediateFuture(RpcResultBuilder.<UnsubscribeDdtlOutput>failed()
+                    .withRpcError(error).build());
         }
 
         ddtlReg.close();
         ddtlReg = null;
 
+        if (!idIntsDdtl.hasTriggered()) {
+            final RpcError error = RpcResultBuilder.newError(
+                    ErrorType.APPLICATION, "No notification received.", "id-ints listener has not received"
+                            + "any notifications.");
+            return Futures.immediateFuture(RpcResultBuilder.<UnsubscribeDdtlOutput>failed()
+                    .withRpcError(error).build());
+        }
+
         final String shardName = ClusterUtils.getCleanShardName(ProduceTransactionsHandler.ID_INTS_YID);
         LOG.debug("Creating distributed datastore client for shard {}", shardName);
 
@@ -612,7 +706,7 @@ public class MdsalLowLevelTestProvider implements OdlMdsalLowlevelControlService
         try {
             distributedDataStoreClient = SimpleDataStoreClientActor
                     .getDistributedDataStoreClient(clientActor, 30, TimeUnit.SECONDS);
-        } catch (final Exception e) {
+        } catch (RuntimeException e) {
             LOG.error("Failed to get actor for {}", distributedDataStoreClientProps, e);
             clientActor.tell(PoisonPill.getInstance(), noSender());
             final RpcError error = RpcResultBuilder.newError(