/** @throws Exception */
  @AfterClass
  public static void tearDownAfterClass() throws Exception {
    String methodName = Utility.getMethodName();
    LoggingUtilities.banner(log, cclass, methodName);

    try {
      if (clientFactory != null) {
        clientFactory.close();
        clientFactory.disconnect();
      }
    } catch (Exception exception) {
      log.log(Level.SEVERE, "caught exception:", exception);
    }
  }
  /** @throws Exception */
  @BeforeClass
  public static void setUpBeforeClass() throws Exception {

    try {
      String methodName = Utility.getMethodName();
      LoggingUtilities.banner(log, cclass, methodName);

      serverURI = TestProperties.getServerURI();
      clientFactory = new MqttClientFactoryPaho();
      clientFactory.open();
    } catch (Exception exception) {
      log.log(Level.SEVERE, "caught exception:", exception);
      throw exception;
    }
  }
 void connectAndSub() {
   String methodName = Utility.getMethodName();
   try {
     mqttClient = clientFactory.createMqttClient(serverURI, ClientId);
     mqttV3Receiver = new MqttV3Receiver(mqttClient, LoggingUtilities.getPrintStream());
     mqttV3Receiver.setReportConnectionLoss(false);
     mqttClient.setCallback(mqttV3Receiver);
     MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
     mqttConnectOptions.setCleanSession(false);
     mqttConnectOptions.setWill("WillTopic", "payload".getBytes(), 2, true);
     log.info("Connecting...(serverURI:" + serverURI + ", ClientId:" + ClientId);
     mqttClient.connect(mqttConnectOptions);
     log.info("Subscribing to..." + FirstSubTopicString);
     mqttClient.subscribe(FirstSubTopicString, 2);
   } catch (Exception exception) {
     log.log(Level.SEVERE, "caugh exception:" + exception);
     setState(FirstClientState.ERROR);
     Assert.fail("Failed ConnectAndSub exception=" + exception);
   }
 }
    void repeatedlyPub() {
      String methodName = Utility.getMethodName();

      int i = 0;
      while (mqttClient.isConnected()) {
        try {
          if (i > 999999) {
            i = 0;
          }
          byte[] payload =
              ("Message payload " + getClass().getName() + ".publish" + (i++)).getBytes();
          MqttTopic mqttTopic = mqttClient.getTopic(FirstSubTopicString);
          log.info("Publishing to..." + FirstSubTopicString);
          mqttTopic.publish(payload, 1, false);

        } catch (Exception exception) {
          log.fine("Caught exception:" + exception);
          // Don't fail - we are going to get an exception as we disconnected during takeOver
          // Its likely the publish rate is too high i.e. inflight window is full
        }
      }
    }
    public void run() {
      String methodName = Utility.getMethodName();
      LoggingUtilities.banner(log, cclass, methodName);
      log.entering(className, methodName);

      connectAndSub();
      try {
        setState(FirstClientState.READY);
        waitForState(FirstClientState.RUNNING);
        repeatedlyPub();
        log.info("FirstClient exiting...");
        log.exiting(className, methodName);

        mqttClient.close();

      } catch (InterruptedException exception) {
        setState(FirstClientState.ERROR);
        log.log(Level.SEVERE, "caught exception:", exception);
      } catch (MqttException exception) {
        setState(FirstClientState.ERROR);
        log.log(Level.SEVERE, "caught exception:", exception);
      }
    }
  /**
   * Test that a client actively doing work can be taken over
   *
   * @throws Exception
   */
  @Test
  public void testLiveTakeOver() throws Exception {
    String methodName = Utility.getMethodName();
    LoggingUtilities.banner(log, cclass, methodName);
    log.entering(className, methodName);

    IMqttClient mqttClient = null;
    try {
      FirstClient firstClient = new FirstClient();
      Thread firstClientThread = new Thread(firstClient);
      log.info("Starting the firstClient thread");
      firstClientThread.start();
      log.info("firstClientThread Started");

      firstClient.waitForState(FirstClientState.READY);

      log.fine("telling the 1st client to go and let it publish for 2 seconds");
      // Tell the first client to go and let it publish for a couple of seconds
      firstClient.setState(FirstClientState.RUNNING);
      Thread.sleep(2000);

      log.fine("Client has been run for 2 seconds, now taking over connection");

      // Now lets take over the connection
      // Create a second MQTT client connection with the same clientid. The
      // server should spot this and kick the first client connection off.
      // To do this from the same box the 2nd client needs to use either
      // a different form of persistent store or a different locaiton for
      // the store to the first client.
      // MqttClientPersistence persist = new MemoryPersistence();
      mqttClient = clientFactory.createMqttClient(serverURI, ClientId, null);

      MqttV3Receiver mqttV3Receiver =
          new MqttV3Receiver(mqttClient, LoggingUtilities.getPrintStream());
      mqttClient.setCallback(mqttV3Receiver);
      MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
      mqttConnectOptions.setCleanSession(false);
      mqttConnectOptions.setWill("WillTopic", "payload".getBytes(), 2, true);
      log.info("Connecting...(serverURI:" + serverURI + ", ClientId:" + ClientId);
      mqttClient.connect(mqttConnectOptions);

      // We should have taken over the first Client's subscription...we may have some
      // of his publishes arrive.
      // NOTE: as a different persistence is used for the second client any inflight
      // publications from the client will not be recovered / restarted. This will
      // leave debris on the server.
      log.fine(
          "We should have taken over the first Client's subscription...we may have some of his publishes arrive.");
      // Ignore his publishes that arrive...
      ReceivedMessage oldMsg;
      do {
        oldMsg = mqttV3Receiver.receiveNext(1000);
      } while (oldMsg != null);

      log.fine("Now check we have grabbed his subscription by publishing..");
      // Now check we have grabbed his subscription by publishing..
      byte[] payload =
          ("Message payload from second client " + getClass().getName() + "." + methodName)
              .getBytes();
      MqttTopic mqttTopic = mqttClient.getTopic(FirstSubTopicString);
      log.info("Publishing to..." + FirstSubTopicString);
      mqttTopic.publish(payload, 1, false);
      log.info("Publish sent, checking for receipt...");

      boolean ok = mqttV3Receiver.validateReceipt(FirstSubTopicString, 1, payload);
      if (!ok) {
        throw new Exception("Receive failed");
      }
    } catch (Exception exception) {
      log.throwing(className, methodName, exception);
      throw exception;
    } finally {
      try {
        mqttClient.disconnect();
        log.info("Disconnecting...");
        mqttClient.close();
        log.info("Close...");
      } catch (Exception exception) {
        log.throwing(className, methodName, exception);
        throw exception;
      }
    }

    log.exiting(className, methodName);
  }