private void sendPendingHaves() {
    if (destroyed) {

      return;
    }

    try {
      pending_haves_mon.enter();

      int num_haves = pending_haves.size();

      if (num_haves == 0) {

        return;
      }

      // single have -> use BT

      if (num_haves == 1 || az_have_version < BTMessageFactory.MESSAGE_VERSION_SUPPORTS_PADDING) {

        for (int i = 0; i < num_haves; i++) {

          Integer piece_num = (Integer) pending_haves.get(i);

          outgoing_message_q.addMessage(new BTHave(piece_num.intValue(), bt_have_version), true);
        }
      } else {

        int[] piece_numbers = new int[num_haves];

        for (int i = 0; i < num_haves; i++) {

          piece_numbers[i] = ((Integer) pending_haves.get(i)).intValue();
        }

        outgoing_message_q.addMessage(new AZHave(piece_numbers, az_have_version), true);
      }

      outgoing_message_q.doListenerNotifications();

      pending_haves.clear();

    } finally {

      pending_haves_mon.exit();
    }
  }
  /** Destroy the aggregator, along with any pending messages. */
  public void destroy() {
    try {
      pending_haves_mon.enter();

      pending_haves.clear();
      destroyed = true;
    } finally {
      pending_haves_mon.exit();
    }
  }
  /**
   * Queue a new have message for aggregated sending.
   *
   * @param piece_number of the have message
   * @param force if true, send this and any other pending haves right away
   */
  public void queueHaveMessage(int piece_number, boolean force) {
    if (destroyed) return;

    try {
      pending_haves_mon.enter();

      pending_haves.add(new Integer(piece_number));
      if (force) {
        sendPendingHaves();
      } else {
        int pending_bytes = pending_haves.size() * 9;
        if (pending_bytes >= outgoing_message_q.getMssSize()) {
          // System.out.println("enough pending haves for a full packet!");
          // there's enough pending bytes to fill a packet payload
          sendPendingHaves();
        }
      }
    } finally {

      pending_haves_mon.exit();
    }
  }
 /**
  * Are there Haves messages pending?
  *
  * @return true if there are any unsent haves, false otherwise
  */
 public boolean hasPending() {
   return !pending_haves.isEmpty();
 }