@Override
  public void connectionFailed(
      final ActiveMQException me, boolean failedOver, String scaleDownTargetNodeID) {
    ActiveMQServerLogger.LOGGER.bridgeConnectionFailed(failedOver);

    synchronized (connectionGuard) {
      keepConnecting = true;
    }

    try {
      if (producer != null) {
        producer.close();
      }

      cleanUpSessionFactory(csf);
    } catch (Throwable dontCare) {
    }

    try {
      session.cleanUp(false);
    } catch (Throwable dontCare) {
    }

    if (scaleDownTargetNodeID != null && !scaleDownTargetNodeID.equals(nodeUUID.toString())) {
      synchronized (this) {
        try {
          logger.debug(
              "Moving "
                  + queue.getMessageCount()
                  + " messages from "
                  + queue.getName()
                  + " to "
                  + scaleDownTargetNodeID);
          ((QueueImpl) queue)
              .moveReferencesBetweenSnFQueues(SimpleString.toSimpleString(scaleDownTargetNodeID));

          // stop the bridge from trying to reconnect and clean up all the bindings
          fail(true);
        } catch (Exception e) {
          ActiveMQServerLogger.LOGGER.warn(e.getMessage(), e);
        }
      }
    } else if (scaleDownTargetNodeID != null) {
      // the disconnected node is scaling down to me, no need to reconnect to it
      logger.debug(
          "Received scaleDownTargetNodeID: " + scaleDownTargetNodeID + "; cancelling reconnect.");
      fail(true);
    } else {
      logger.debug("Received invalid scaleDownTargetNodeID: " + scaleDownTargetNodeID);

      fail(me.getType() == ActiveMQExceptionType.DISCONNECTED);
    }

    tryScheduleRetryReconnect(me.getType());
  }
  protected void scheduleRetryConnect() {
    if (serverLocator.isClosed()) {
      ActiveMQServerLogger.LOGGER.bridgeLocatorShutdown();
      return;
    }

    if (stopping) {
      ActiveMQServerLogger.LOGGER.bridgeStopping();
      return;
    }

    if (reconnectAttemptsInUse >= 0 && retryCount > reconnectAttemptsInUse) {
      ActiveMQServerLogger.LOGGER.bridgeAbortStart(name, retryCount, reconnectAttempts);
      fail(true);
      return;
    }

    long timeout = (long) (this.retryInterval * Math.pow(this.retryMultiplier, retryCount));
    if (timeout == 0) {
      timeout = this.retryInterval;
    }
    if (timeout > maxRetryInterval) {
      timeout = maxRetryInterval;
    }

    logger.debug(
        "Bridge "
            + this
            + " retrying connection #"
            + retryCount
            + ", maxRetry="
            + reconnectAttemptsInUse
            + ", timeout="
            + timeout);

    scheduleRetryConnectFixedTimeout(timeout);
  }
  /* This is called only when the bridge is activated */
  protected void connect() {
    if (stopping) return;

    synchronized (connectionGuard) {
      if (!keepConnecting) return;

      logger.debug(
          "Connecting  "
              + this
              + " to its destination ["
              + nodeUUID.toString()
              + "], csf="
              + this.csf);

      retryCount++;

      try {
        if (csf == null || csf.isClosed()) {
          if (stopping) return;
          csf = createSessionFactory();
          if (csf == null) {
            // Retrying. This probably means the node is not available (for the cluster connection
            // case)
            scheduleRetryConnect();
            return;
          }
          // Session is pre-acknowledge
          session =
              (ClientSessionInternal) csf.createSession(user, password, false, true, true, true, 1);
          sessionConsumer =
              (ClientSessionInternal) csf.createSession(user, password, false, true, true, true, 1);
        }

        if (forwardingAddress != null) {
          ClientSession.AddressQuery query = null;

          try {
            query = session.addressQuery(forwardingAddress);
          } catch (Throwable e) {
            ActiveMQServerLogger.LOGGER.errorQueryingBridge(e, name);
            // This was an issue during startup, we will not count this retry
            retryCount--;

            scheduleRetryConnectFixedTimeout(100);
            return;
          }

          if (forwardingAddress.startsWith(BridgeImpl.JMS_QUEUE_ADDRESS_PREFIX)
              || forwardingAddress.startsWith(BridgeImpl.JMS_TOPIC_ADDRESS_PREFIX)) {
            if (!query.isExists()) {
              ActiveMQServerLogger.LOGGER.errorQueryingBridge(forwardingAddress, retryCount);
              scheduleRetryConnect();
              return;
            }
          } else {
            if (!query.isExists()) {
              ActiveMQServerLogger.LOGGER.bridgeNoBindings(
                  getName(), getForwardingAddress(), getForwardingAddress());
            }
          }
        }

        producer = session.createProducer();
        session.addFailureListener(BridgeImpl.this);

        session.setSendAcknowledgementHandler(BridgeImpl.this);

        afterConnect();

        active = true;

        queue.addConsumer(BridgeImpl.this);
        queue.deliverAsync();

        ActiveMQServerLogger.LOGGER.bridgeConnected(this);

        // We only do this on plain core bridges
        if (isPlainCoreBridge()) {
          serverLocator.addClusterTopologyListener(new TopologyListener());
        }

        keepConnecting = false;
        return;
      } catch (ActiveMQException e) {
        // the session was created while its server was starting, retry it:
        if (e.getType() == ActiveMQExceptionType.SESSION_CREATION_REJECTED) {
          ActiveMQServerLogger.LOGGER.errorStartingBridge(name);

          // We are not going to count this one as a retry
          retryCount--;

          scheduleRetryConnectFixedTimeout(this.retryInterval);
          return;
        } else {
          if (logger.isDebugEnabled()) {
            logger.debug("Bridge " + this + " is unable to connect to destination. Retrying", e);
          }

          scheduleRetryConnect();
        }
      } catch (ActiveMQInterruptedException | InterruptedException e) {
        ActiveMQServerLogger.LOGGER.errorConnectingBridge(e, this);
      } catch (Exception e) {
        ActiveMQServerLogger.LOGGER.errorConnectingBridge(e, this);
        if (csf != null) {
          try {
            csf.close();
            csf = null;
          } catch (Throwable ignored) {
          }
        }
        fail(false);
        scheduleRetryConnect();
      }
    }
  }