@Override
  public BasicCoapResponse createResponse(
      CoapMessage request, CoapResponseCode responseCode, CoapMediaType contentType) {
    BasicCoapResponse response;
    if (request.getPacketType() == CoapPacketType.CON) {
      response =
          new BasicCoapResponse(
              CoapPacketType.ACK, responseCode, request.getMessageID(), request.getToken());
    } else if (request.getPacketType() == CoapPacketType.NON) {
      response =
          new BasicCoapResponse(
              CoapPacketType.NON, responseCode, request.getMessageID(), request.getToken());
    } else {
      throw new IllegalStateException(
          "Create Response failed, Request is neither a CON nor a NON packet");
    }
    if (contentType != null && contentType != CoapMediaType.UNKNOWN) {
      response.setContentType(contentType);
    }

    response.setChannel(this);
    return response;
  }
  public void handleMessage(CoapMessage message) {
    if (message.isRequest()) {
      /* this is a client channel, no requests allowed */
      message
          .getChannel()
          .sendMessage(new CoapEmptyMessage(CoapPacketType.RST, message.getMessageID()));
      return;
    }

    if (message.isEmpty() && message.getPacketType() == CoapPacketType.ACK) {
      /* this is the ACK of a separate response */
      // TODO: implement a handler or listener, that informs a client when a sep. resp. ack was
      // received
      return;
    }

    if (message.getPacketType() == CoapPacketType.CON) {
      /* this is a separate response */
      /* send ACK */
      this.sendMessage(new CoapEmptyMessage(CoapPacketType.ACK, message.getMessageID()));
    }

    /* check for blockwise transfer */
    CoapBlockOption block2 = message.getBlock2();
    if (blockContext == null && block2 != null) {
      /* initiate blockwise transfer */
      blockContext = new ClientBlockContext(block2, maxReceiveBlocksize);
      blockContext.setFirstRequest(lastRequest);
      blockContext.setFirstResponse((CoapResponse) message);
    }

    if (blockContext != null) {
      /*blocking option*/
      if (!blockContext.addBlock(message, block2)) {
        /*this was not a correct block*/
        /* TODO: implement either a RST or ignore this packet */
      }

      if (!blockContext.isFinished()) {
        /* TODO: implement a counter to avoid an infinity req/resp loop:
         *  		if the same block is received more than x times -> rst the connection
         *  implement maxPayloadSize to avoid an infinity payload */
        CoapBlockOption newBlock = blockContext.getNextBlock();
        if (lastRequest == null) {
          /*TODO: this should never happen*/
          System.out.println("ERROR: client channel: lastRequest == null");
        } else {
          /* create a new request for the next block */
          BasicCoapRequest request =
              new BasicCoapRequest(
                  lastRequest.getPacketType(),
                  lastRequest.getRequestCode(),
                  channelManager.getNewMessageID());
          request.copyHeaderOptions((BasicCoapRequest) blockContext.getFirstRequest());
          request.setBlock2(newBlock);
          sendMessage(request);
        }
        /* TODO: implement handler, inform the client that a block (but not the complete message) was received*/
        return;
      }
      /* blockwise transfer finished */
      message.setPayload(blockContext.getPayload());
      /* TODO: give the payload separately and leave the original message as they is*/
    }

    /* normal or separate response */
    client.onResponse(this, (BasicCoapResponse) message);
  }