/**
   * This method deals with messages arrived as regular message but its contents are compressed.
   * Such messages come from message senders who are configured to compress large messages, and if
   * some of the messages are compressed below the min-large-message-size limit, they are sent as
   * regular messages. <br>
   * However when decompressing the message, we are not sure how large the message could be.. for
   * that reason we fake a large message controller that will deal with the message as it was a
   * large message <br>
   * Say that you sent a 1G message full of spaces. That could be just bellow 100K compressed but
   * you wouldn't have enough memory to decompress it
   */
  private void handleCompressedMessage(final ClientMessageInternal clMessage) throws Exception {
    ClientLargeMessageImpl largeMessage = new ClientLargeMessageImpl();
    largeMessage.retrieveExistingData(clMessage);

    File largeMessageCache = null;

    if (session.isCacheLargeMessageClient()) {
      largeMessageCache =
          File.createTempFile("tmp-large-message-" + largeMessage.getMessageID() + "-", ".tmp");
      largeMessageCache.deleteOnExit();
    }

    ClientSessionFactory sf = session.getSessionFactory();
    ServerLocator locator = sf.getServerLocator();
    long callTimeout = locator.getCallTimeout();

    currentLargeMessageController =
        new LargeMessageControllerImpl(
            this, largeMessage.getLargeMessageSize(), callTimeout, largeMessageCache);
    currentLargeMessageController.setLocal(true);

    // sets the packet
    ActiveMQBuffer qbuff = clMessage.getBodyBuffer();
    int bytesToRead = qbuff.writerIndex() - qbuff.readerIndex();
    final byte[] body = qbuff.readBytes(bytesToRead).toByteBuffer().array();

    largeMessage.setLargeMessageController(
        new CompressedLargeMessageControllerImpl(currentLargeMessageController));
    currentLargeMessageController.addPacket(body, body.length, false);

    handleRegularMessage(largeMessage);
  }
  public void decode(final ActiveMQBuffer buffer) {
    channelID = buffer.readLong();

    decodeRest(buffer);

    size = buffer.readerIndex();
  }
  public void write(
      final ActiveMQBuffer buffer,
      final boolean flush,
      final boolean batch,
      final ChannelFutureListener futureListener) {
    final ActiveMQBuffer copied = buffer.copy(0, buffer.capacity());

    copied.setIndex(buffer.readerIndex(), buffer.writerIndex());

    try {
      executor.execute(
          new Runnable() {
            public void run() {
              try {
                if (!closed) {
                  copied.readInt(); // read and discard
                  if (isTrace) {
                    ActiveMQServerLogger.LOGGER.trace(
                        InVMConnection.this + "::Sending inVM packet");
                  }
                  handler.bufferReceived(id, copied);
                  if (futureListener != null) {
                    // TODO BEFORE MERGE: (is null a good option here?)
                    futureListener.operationComplete(null);
                  }
                }
              } catch (Exception e) {
                final String msg = "Failed to write to handler on connector " + this;
                ActiveMQServerLogger.LOGGER.errorWritingToInvmConnector(e, this);
                throw new IllegalStateException(msg, e);
              } finally {
                if (isTrace) {
                  ActiveMQServerLogger.LOGGER.trace(InVMConnection.this + "::packet sent done");
                }
              }
            }
          });

      if (flush && flushEnabled) {
        final CountDownLatch latch = new CountDownLatch(1);
        executor.execute(
            new Runnable() {
              public void run() {
                latch.countDown();
              }
            });

        try {
          if (!latch.await(10, TimeUnit.SECONDS)) {
            ActiveMQServerLogger.LOGGER.timedOutFlushingInvmChannel();
          }
        } catch (InterruptedException e) {
          throw new ActiveMQInterruptedException(e);
        }
      }
    } catch (RejectedExecutionException e) {
      // Ignore - this can happen if server/client is shutdown and another request comes in
    }
  }