/**
   * Makes sure that the response type is correct. The response type for a NON can be NON or CON.
   * The response type for a CON should either be an ACK with a piggy-backed response or, if an
   * empty ACK has already be sent, a CON or NON with a separate response.
   */
  @Override
  public void sendResponse(final Exchange exchange, final Response response) {

    LOGGER.finer("Send response, failed transmissions: " + exchange.getFailedTransmissionCount());

    // If a response type is set, we do not mess around with it.
    // Only if none is set, we have to decide for one here.

    Type respType = response.getType();
    if (respType == null) {
      Type reqType = exchange.getCurrentRequest().getType();
      if (reqType == Type.CON) {
        if (exchange.getCurrentRequest().isAcknowledged()) {
          // send separate response
          response.setType(Type.CON);
        } else {
          exchange.getCurrentRequest().setAcknowledged(true);
          // send piggy-backed response
          response.setType(Type.ACK);
          response.setMID(exchange.getCurrentRequest().getMID());
        }
      } else {
        // send NON response
        response.setType(Type.NON);
      }

      LOGGER.finest(
          "Switched response message type from "
              + respType
              + " to "
              + response.getType()
              + " (request was "
              + reqType
              + ")");

    } else if (respType == Type.ACK || respType == Type.RST) {
      response.setMID(exchange.getCurrentRequest().getMID());
    }

    if (response.getType() == Type.CON) {
      LOGGER.finer("Scheduling retransmission for " + response);
      prepareRetransmission(
          exchange,
          new RetransmissionTask(exchange, response) {
            public void retransmit() {
              sendResponse(exchange, response);
            }
          });
    }
    super.sendResponse(exchange, response);
  }
  /**
   * This method is used to apply resource-specific knowledge on the exchange. If the request was
   * successful, it sets the Observe option for the response. It is important to use the
   * notificationOrderer of the resource here. Further down the layer, race conditions could cause
   * local reordering of notifications. If the response has an error code, no observe relation can
   * be established and if there was one previously it is canceled. When this resource allows to be
   * observed by clients and the request is a GET request with an observe option, the {@link
   * ServerMessageDeliverer} already created the relation, as it manages the observing endpoints
   * globally.
   *
   * @param exchange the exchange
   * @param response the response
   */
  public void checkObserveRelation(Exchange exchange, Response response) {
    /*
     * If the request for the specified exchange tries to establish an observer
     * relation, then the ServerMessageDeliverer must have created such a relation
     * and added to the exchange. Otherwise, there is no such relation.
     * Remember that different paths might lead to this resource.
     */

    ObserveRelation relation = exchange.getRelation();
    if (relation == null) return; // because request did not try to establish a relation

    if (CoAP.ResponseCode.isSuccess(response.getCode())) {
      response.getOptions().setObserve(notificationOrderer.getCurrent());

      if (!relation.isEstablished()) {
        relation.setEstablished(true);
        addObserveRelation(relation);
      } else if (observeType != null) {
        // The resource can control the message type of the notification
        response.setType(observeType);
      }
    } // ObserveLayer takes care of the else case
  }