code: public synchronized Map.Entry<Short, Packet<T>> send(T data) {
          Packet<T> packet = controller.produce();
          if (shouldRetransmit) {
              Collection<Metadata<T>> retransmits = controller.retransmit();
              for (Metadata<T> retransmit : retransmits) {
                  controller.send(packet, retransmit);
              }
          }
          if (data != null)
              controller.send(packet, controller.produce(data));
  
          sentPacketOut.packet = packet;
          sentPacketOut.id = data != null ? packet.getLastMetadata().getDataId() : null;
          return sentPacketOut;
      }
docs: Package the user-data, in order to transmit the user-data, acknowledge
  received data and retransmit data (if {@link ProtocolConfig#setShouldRetransmit(boolean) retransmission is enabled}).
  <br>
  Zero or more {@link ProtocolListener#handleUnackedData(short, Object) unackedData} events may be fired before
  this method returns.
  
  @param data the user-data to package, if it's <code>null</code> no user-data will be contained in the package
  @return a <code>Map.Entry</code> containing the {@link Packet packaged user-data} and
  the <code>dataId</code> that was assigned to the user-data;
  the returned mapEntry should not be saved by the user,
  as its contents are invalidated next time one of the <code>send</code> methods is called