/**
   * @param destination Member[] - destination.length > 0
   * @param msg Serializable - the message to send
   * @param options sender options, options can trigger guarantee levels and different interceptors
   *     to react to the message see class documentation for the <code>Channel</code> object.<br>
   * @param handler - callback object for error handling and completion notification, used when a
   *     message is sent asynchronously using the <code>Channel.SEND_OPTIONS_ASYNCHRONOUS</code>
   *     flag enabled.
   * @return UniqueId - the unique Id that was assigned to this message
   * @throws ChannelException - if an error occurs processing the message
   * @see org.apache.catalina.tribes.Channel
   */
  @Override
  public UniqueId send(Member[] destination, Serializable msg, int options, ErrorHandler handler)
      throws ChannelException {
    if (msg == null) throw new ChannelException(sm.getString("groupChannel.nullMessage"));
    XByteBuffer buffer = null;
    try {
      if (destination == null || destination.length == 0) {
        throw new ChannelException(sm.getString("groupChannel.noDestination"));
      }
      ChannelData data = new ChannelData(true); // generates a unique Id
      data.setAddress(getLocalMember(false));
      data.setTimestamp(System.currentTimeMillis());
      byte[] b = null;
      if (msg instanceof ByteMessage) {
        b = ((ByteMessage) msg).getMessage();
        options = options | SEND_OPTIONS_BYTE_MESSAGE;
      } else {
        b = XByteBuffer.serialize(msg);
        options = options & (~SEND_OPTIONS_BYTE_MESSAGE);
      }
      data.setOptions(options);
      // XByteBuffer buffer = new XByteBuffer(b.length+128,false);
      buffer = BufferPool.getBufferPool().getBuffer(b.length + 128, false);
      buffer.append(b, 0, b.length);
      data.setMessage(buffer);
      InterceptorPayload payload = null;
      if (handler != null) {
        payload = new InterceptorPayload();
        payload.setErrorHandler(handler);
      }
      getFirstInterceptor().sendMessage(destination, data, payload);
      if (Logs.MESSAGES.isTraceEnabled()) {
        Logs.MESSAGES.trace(
            "GroupChannel - Sent msg:"
                + new UniqueId(data.getUniqueId())
                + " at "
                + new java.sql.Timestamp(System.currentTimeMillis())
                + " to "
                + Arrays.toNameString(destination));
        Logs.MESSAGES.trace(
            "GroupChannel - Send Message:" + new UniqueId(data.getUniqueId()) + " is " + msg);
      }

      return new UniqueId(data.getUniqueId());
    } catch (Exception x) {
      if (x instanceof ChannelException) throw (ChannelException) x;
      throw new ChannelException(x);
    } finally {
      if (buffer != null) BufferPool.getBufferPool().returnBuffer(buffer);
    }
  }