/**
   * If we receive an ACK or RST, we mark the outgoing request or response as acknowledged or
   * rejected respectively and cancel its retransmission.
   */
  @Override
  public void receiveEmptyMessage(Exchange exchange, EmptyMessage message) {
    exchange.setFailedTransmissionCount(0);
    // TODO: If this is an observe relation, the current response might not
    // be the one that is being acknowledged. The current response might
    // already be the next NON notification.

    if (message.getType() == Type.ACK) {
      if (exchange.getOrigin() == Origin.LOCAL) {
        exchange.getCurrentRequest().setAcknowledged(true);
      } else {
        exchange.getCurrentResponse().setAcknowledged(true);
      }
    } else if (message.getType() == Type.RST) {
      if (exchange.getOrigin() == Origin.LOCAL) {
        exchange.getCurrentRequest().setRejected(true);
      } else {
        exchange.getCurrentResponse().setRejected(true);
      }
    } else {
      LOGGER.warning("Empty messgae was not ACK nor RST: " + message);
    }

    LOGGER.finer("Cancel retransmission");
    exchange.setRetransmissionHandle(null);

    super.receiveEmptyMessage(exchange, message);
  }
    @Override
    public void run() {
      /*
       * Do not retransmit a message if it has been acknowledged,
       * rejected, canceled or already been retransmitted for the maximum
       * number of times.
       */
      try {
        int failedCount = exchange.getFailedTransmissionCount() + 1;
        exchange.setFailedTransmissionCount(failedCount);

        if (message.isAcknowledged()) {
          LOGGER.finest(
              "Timeout: message already acknowledged, cancel retransmission of " + message);
          return;

        } else if (message.isRejected()) {
          LOGGER.finest("Timeout: message already rejected, cancel retransmission of " + message);
          return;

        } else if (message.isCanceled()) {
          LOGGER.finest("Timeout: canceled (MID=" + message.getMID() + "), do not retransmit");
          return;

        } else if (failedCount <= max_retransmit) {
          LOGGER.finer(
              "Timeout: retransmit message, failed: " + failedCount + ", message: " + message);

          // Trigger MessageObservers
          message.retransmitting();

          // MessageObserver might have canceled
          if (!message.isCanceled()) retransmit();

        } else {
          LOGGER.info(
              "Timeout: retransmission limit reached, exchange failed, message: " + message);
          exchange.setTimedOut();
          message.setTimedOut(true);
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  /**
   * When we receive a Confirmable response, we acknowledge it and it also counts as acknowledgment
   * for the request. If the response is a duplicate, we stop it here and do not forward it to the
   * upper layer.
   */
  @Override
  public void receiveResponse(Exchange exchange, Response response) {
    exchange.setFailedTransmissionCount(0);

    exchange.getCurrentRequest().setAcknowledged(true);
    LOGGER.finest("Cancel any retransmission");
    exchange.setRetransmissionHandle(null);

    if (response.getType() == Type.CON && !exchange.getRequest().isCanceled()) {
      LOGGER.finer("Response is confirmable, send ACK");
      EmptyMessage ack = EmptyMessage.newACK(response);
      sendEmptyMessage(exchange, ack);
    }

    if (response.isDuplicate()) {
      LOGGER.fine("Response is duplicate, ignore it");
    } else {
      super.receiveResponse(exchange, response);
    }
  }