public BasicCoapRequest createRequest(boolean reliable, CoapRequestCode requestCode) {
   BasicCoapRequest msg =
       new BasicCoapRequest(
           reliable ? CoapPacketType.CON : CoapPacketType.NON,
           requestCode,
           channelManager.getNewMessageID());
   msg.setChannel(this);
   return msg;
 }
  @Override
  public void handleMessage(CoapMessage message) {
    /* message MUST be a request */
    if (message.isEmpty()) {
      return;
    }

    if (!message.isRequest()) {
      return;
      // throw new IllegalStateException("Incomming server message is not a request");
    }

    BasicCoapRequest request = (BasicCoapRequest) message;
    CoapChannel channel = request.getChannel();
    /* TODO make this cast safe */
    server.onRequest((CoapServerChannel) channel, request);
  }
  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);
  }